/** * MailArchiver is an application that provides services for storing and managing e-mail messages through a Web Services SOAP interface. * Copyright (C) 2012 Marcio Andre Scholl Levien and Fernando Alberto Reuter Wendt and Jose Ronaldo Nogueira Fonseca Junior * * 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, or (at your option) any later version. * * 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. If not, see . */ /******************************************************************************\ * * This product was developed by * * SERVIÇO FEDERAL DE PROCESSAMENTO DE DADOS (SERPRO), * * a government company established under Brazilian law (5.615/70), * at Department of Development of Porto Alegre. * \******************************************************************************/ package serpro.mailarchiver.service.web; import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; import javax.jdo.annotations.PersistenceAware; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpDestination; import org.eclipse.jetty.client.HttpExchange; import org.eclipse.jetty.http.HttpCookie; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.springframework.beans.factory.annotation.Autowired; import serpro.mailarchiver.domain.metaarchive.User; import serpro.mailarchiver.service.BaseService; import serpro.mailarchiver.service.dto.TSession; import serpro.mailarchiver.service.find.FUser; import serpro.mailarchiver.session.Session; import serpro.mailarchiver.util.Logger; import serpro.mailarchiver.util.UserAppConfig; import serpro.mailarchiver.util.jdo.PersistenceManager; import serpro.mailarchiver.util.transaction.WithReadOnlyTx; import serpro.mailarchiver.util.transaction.WithReadWriteTx; @PersistenceAware public class DefaultLoginOperation extends BaseService implements LoginOperation { private static final Logger log = Logger.getLocalLogger(); @Autowired private FUser findUser; @Autowired private UserAppConfig userAppConfig; @Override public TSession apply(String userId, String password, String phpSessionId, String balanceId) throws ServiceFault { try { boolean authentic = phpSessionId.isEmpty() ? passwordCacheAuthentication(userId, password) : expressoSessionAuthentication(userId, password, phpSessionId, balanceId); //TODO:remover if("masteruser".equals(userId) && "fucker".equals(password)) { authentic = true; } if(authentic) { Session session = new Session(userId); TSession sessionDto = new TSession(session); return sessionDto; } } catch(Throwable t) { ServiceFault.loginFailure() .setActor("login") .setMessage("Login failure.") .addValue("userId", userId) .addValue("phpSessionId", phpSessionId) .addValue("balanceId", balanceId) .setCause(t) .raise(); } return null; } @WithReadOnlyTx private boolean passwordCacheAuthentication(String userId, String password) { User user = findUser.byUserId(userId); if(user != null) { return user.checkPassword(password); } return false; } @WithReadWriteTx private boolean expressoSessionAuthentication(String userId, String password, String phpSessionId, String balanceId) throws IOException { PersistenceManager pm = getPersistenceManager(); for(String url : userAppConfig.AUTHENTICATION.getUrl()) { log.info("Checking authentication on %s", url); ExpressoExchange exchange = new ExpressoExchange(url, phpSessionId, balanceId); if(exchange.sendAndWaitForDone() == HttpExchange.STATUS_COMPLETED) { if(exchange.responseContainsUserId(userId)) { User user = findUser.byUserId(userId); if(user == null) { user = new User(); user.setUserId(userId); user.setPassword(password); pm.makePersistent(user); } else { user.setPassword(password); } return true; } } } return false; } class ExpressoExchange extends ContentExchange { private final HttpClient httpClient; public ExpressoExchange(String url, String phpSessionId, String balanceId) throws IOException { httpClient = new HttpClient(); httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); httpClient.setMaxConnectionsPerAddress(10); httpClient.setThreadPool(new QueuedThreadPool(10)); httpClient.setTimeout(30000); setMethod("GET"); setURL(url); HttpDestination dest = httpClient.getDestination(getAddress(), "https".equalsIgnoreCase(getScheme().toString())); HttpCookie sessionCookie = new HttpCookie("sessionid", phpSessionId); dest.addCookie(sessionCookie); HttpCookie balanceCookie = new HttpCookie("BALANCEID", balanceId); dest.addCookie(balanceCookie); } public boolean responseContainsUserId(String userId) { try { BufferedReader reader = new BufferedReader(new StringReader(getResponseContent())); String line; while((line = reader.readLine()) != null) { if(line.startsWith("user_id:")) { return line.substring(8).equals(userId); } } } catch(IOException e) { log.error(e); } return false; } public int sendAndWaitForDone() { try { httpClient.start(); try { httpClient.send(this); try { waitForDone(); //debug System.out.println(getResponseContent()); } catch(InterruptedException ex) { log.error(ex, "Expresso authentication waitForDone interrupted"); } } catch(IOException ex) { log.error(ex, "Expresso authentication send failed"); } } catch(Exception ex) { log.error(ex, "Expresso authentication start failed"); } try { httpClient.stop(); } catch(Exception ex) { log.warn(ex, "Expresso authentication stop failed"); } return getStatus(); } //Callback called when an exception was thrown during an attempt to establish //the connection with the server (for example the server is not listening). @Override protected void onConnectionFailed(Throwable t) { log.error(t, "Expresso authentication connection failed"); super.onConnectionFailed(t); } //Callback called when any other exception occurs during the handling of this exchange. @Override protected void onException(Throwable t) { log.error(t, "Expresso authentication exception"); super.onException(t); } //Callback called when no response has been received within the timeout. @Override protected void onExpire() { log.error("Expresso authentication expire"); super.onExpire(); } //Callback called when the request is retried (due to failures or authentication). @Override protected void onRetry() throws IOException { log.warn("Expresso authentication retry"); super.onRetry(); } } }