package pt.iscte.ci.authentication; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; import net.sourceforge.fenixedu._development.PropertiesManager; import net.sourceforge.fenixedu.applicationTier.Servico.ExcepcaoAutenticacao; import net.sourceforge.fenixedu.domain.Person; public class PopUtils { private static final String CHECK_POP_SERVER; private static final String POP_TIMEOUT = "pop.timeout"; private final static String POP_SERVER = "pop.server"; private final static String POP_PORT = "pop.port"; private static String popServer = "pop.iscte.pt"; private static int popPort = 110; private static final String BAD_AUTHENTICATION = "bad.authentication"; private static final int SO_TIMEOUT = 60000; private static int popTimeOut = SO_TIMEOUT; static { CHECK_POP_SERVER = PropertiesManager.getProperty("pop.check.enabled"); if (PropertiesManager.getProperty(POP_SERVER) != null) popServer = PropertiesManager.getProperty(POP_SERVER); if (PropertiesManager.getProperty(POP_PORT) != null) popPort = PropertiesManager.getIntegerProperty(POP_PORT); if (PropertiesManager.getProperty(POP_TIMEOUT) != null) popTimeOut = PropertiesManager.getIntegerProperty(POP_TIMEOUT); } public static void authenticate(final Person person, final String username, final String password) throws ExcepcaoAutenticacao { if (!checkPop()) { return; } Socket popHost = null; PopComm popComm = null; try { popHost = new Socket(popServer, popPort); popComm = new PopComm(popHost, popTimeOut); if (login(popComm, username, password)) { return; } throw new ExcepcaoAutenticacao(BAD_AUTHENTICATION + ": " + username); } catch (IOException e) { throw new ExcepcaoAutenticacao("error.communication.with.pop", e); } finally { if (popComm != null) popComm.endConversation(); } } public static class PopComm { private Socket socket; private BufferedReader is; private BufferedOutputStream os; private static final String OK_MESSAGE = "+OK"; private static final String ERR_MESSAGE = "-ERR"; public PopComm(Socket socket, int timeoutReadWrite) throws IOException { this.socket = socket; this.is = new BufferedReader(new InputStreamReader(socket.getInputStream(), "us-ascii")); this.os = new BufferedOutputStream(socket.getOutputStream()); socket.setKeepAlive(false); socket.setTcpNoDelay(true); socket.setSoTimeout(timeoutReadWrite); // Read the first hello line and discard it isResponseOK(); } public void endConversation() { try { sayToPop("quit"); } catch (Exception ignore) { } try { is.close(); } catch (Exception ignore) { } try { os.close(); } catch (Exception ignore) { } try { socket.close(); } catch (Exception ignore) { } } private boolean isResponseOK() throws IOException { String lineRead = null; lineRead = is.readLine(); // System.out.println("read line "+lineRead); // System.out.flush(); if (lineRead != null && lineRead.startsWith(OK_MESSAGE)) return true; else if (lineRead != null && lineRead.startsWith(ERR_MESSAGE)) return false; else throw new IOException("Unknown message '" + lineRead + "' received from pop server!"); } private void writeMessage(String message) throws IOException { // System.out.println("write line "+message); // System.out.flush(); byte[] dataBytes = (message + "\r\n").getBytes("us-ascii"); os.write(dataBytes); os.flush(); } public boolean sayToPop(String message) throws IOException { writeMessage(message); return isResponseOK(); } } // TODO: Access directly the database? private static boolean login(final PopComm popComm, final String username, final String password) throws IOException { if (!popComm.sayToPop("USER " + username)) return false; if (!popComm.sayToPop("PASS " + password)) return false; return true; } /** * * @return Returns true if an access to the email server database should be * performed. It returns false otherwise. This method returns the * property set in the build configuration file, where one specifies * if this should be enabled or not. */ public static boolean checkPop() { return CHECK_POP_SERVER == null || "true".equals(CHECK_POP_SERVER); } }