/** * Aptana Studio * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions). * Please see the license.html included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ // $codepro.audit.disable closeWhereCreated // $codepro.audit.disable variableDeclaredInLoop // $codepro.audit.disable questionableAssignment // $codepro.audit.disable exceptionUsage.exceptionCreation package com.aptana.filesystem.secureftp.internal; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; import java.text.MessageFormat; import java.util.Arrays; import java.util.List; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.PerformanceStats; import org.eclipse.core.runtime.Status; import com.aptana.core.logging.IdeLog; import com.aptana.filesystem.ftp.FTPPlugin; import com.aptana.filesystem.ftp.IFTPConstants; import com.aptana.filesystem.ftp.Policy; import com.aptana.filesystem.ftp.internal.FTPClientPool; import com.aptana.filesystem.ftp.internal.FTPConnectionFileManager; import com.aptana.filesystem.secureftp.IFTPSConnectionFileManager; import com.aptana.filesystem.secureftp.IFTPSConstants; import com.aptana.ide.core.io.ConnectionContext; import com.aptana.ide.core.io.CoreIOPlugin; import com.enterprisedt.net.ftp.FTPClient; import com.enterprisedt.net.ftp.FTPClientInterface; import com.enterprisedt.net.ftp.FTPConnectMode; import com.enterprisedt.net.ftp.FTPException; import com.enterprisedt.net.ftp.FTPTransferType; import com.enterprisedt.net.ftp.ssl.SSLFTPCertificateException; import com.enterprisedt.net.ftp.ssl.SSLFTPClient; import com.enterprisedt.net.ftp.ssl.SSLFTPClient.ConfigFlags; /** * @author Max Stepanov * */ public class FTPSConnectionFileManager extends FTPConnectionFileManager implements IFTPSConnectionFileManager { private boolean validateCertificate; private boolean noSSLSessionResumption; private String securityMechanism; /* (non-Javadoc) * @see com.aptana.filesystem.secureftp.FTPConnectionFileManager#init(java.lang.String, int, org.eclipse.core.runtime.IPath, java.lang.String, char[], boolean, java.lang.String, java.lang.String, java.lang.String) */ @Override public void init(String host, int port, IPath basePath, String login, char[] password, boolean passive, String transferType, String encoding, String timezone) { throw new UnsupportedOperationException(); } /* (non-Javadoc) * @see com.aptana.filesystem.secureftp.IFTPSConnectionFileManager#init(java.lang.String, int, org.eclipse.core.runtime.IPath, java.lang.String, char[], boolean, boolean, java.lang.String, java.lang.String, java.lang.String, boolean, boolean) */ public void init(String host, int port, IPath basePath, String login, char[] password, boolean explicit, boolean passive, String transferType, String encoding, String timezone, boolean validateCertificate, boolean noSSLSessionResumption) { Assert.isTrue(ftpClient == null, Messages.FTPSConnectionFileManager_ConnectionHasBeenInitiated); try { this.pool = new FTPClientPool(this); ftpClient = newClient(); this.host = host; this.port = port; this.login = login; this.password = (password == null) ? EMPTY_PASSWORD : password; this.basePath = (basePath != null) ? basePath : Path.ROOT; this.authId = Policy.generateAuthId("FTPS", login, host, port); //$NON-NLS-1$ this.transferType = transferType; this.timezone = (timezone != null && timezone.length() == 0) ? null : timezone; this.validateCertificate = validateCertificate; this.noSSLSessionResumption = noSSLSessionResumption; initFTPSClient((SSLFTPClient) ftpClient, explicit, passive, encoding, validateCertificate, noSSLSessionResumption); } catch (Exception e) { SecureFTPPlugin.log(new Status(IStatus.WARNING, SecureFTPPlugin.PLUGIN_ID, Messages.FTPSConnectionFileManager_ConnectionInitializationFailed, e)); ftpClient = null; } } protected static void initFTPSClient(SSLFTPClient ftpsClient, boolean explicit, boolean passive, String encoding, boolean validateCertificate, boolean noSSLSessionResumption) throws IOException, FTPException { initFTPClient(ftpsClient, passive, encoding); ftpsClient.setImplicitFTPS(true); ftpsClient.setCustomValidator(new SSLHostValidator()); ftpsClient.setValidateServer(validateCertificate); try { ftpsClient.getRootCertificateStore().importDefaultKeyStore(); } catch (Exception e) { IdeLog.logWarning(SecureFTPPlugin.getDefault(), "Loading default root certificates failed.", e); //$NON-NLS-1$ } ftpsClient.setImplicitFTPS(!explicit); ftpsClient.setConfigFlags(ConfigFlags.START_WITH_CLEAR_DATA_CHANNELS | (noSSLSessionResumption ? ConfigFlags.DISABLE_SESSION_RESUMPTION : 0)); } /* (non-Javadoc) * @see com.aptana.filesystem.secureftp.FTPConnectionFileManager#connect(org.eclipse.core.runtime.IProgressMonitor) */ @Override public void connect(IProgressMonitor monitor) throws CoreException { Assert.isTrue(ftpClient != null, Messages.FTPSConnectionFileManager_ConnectionNotInitialized); SSLFTPClient ftpsClient = (SSLFTPClient) ftpClient; monitor = Policy.monitorFor(monitor); try { cwd = null; cleanup(); ConnectionContext context = CoreIOPlugin.getConnectionContext(this); if (messageLogWriter == null) { if (context != null) { Object object = context.get(ConnectionContext.COMMAND_LOG); if (object instanceof PrintWriter) { messageLogWriter = (PrintWriter) object; } else if (object instanceof OutputStream) { messageLogWriter = new PrintWriter((OutputStream) object); } } if (messageLogWriter == null) { messageLogWriter = FTPPlugin.getDefault().getFTPLogWriter(); } if (messageLogWriter != null) { messageLogWriter.println(MessageFormat.format("---------- FTPS {0} ----------", host)); //$NON-NLS-1$ setMessageLogger(ftpClient, messageLogWriter); } } else { messageLogWriter.println(MessageFormat.format("---------- RECONNECTING - FTPS {0} ----------", host)); //$NON-NLS-1$ } monitor.beginTask(Messages.FTPSConnectionFileManager_EstablishingConnection, IProgressMonitor.UNKNOWN); ftpClient.setRemoteHost(host); ftpClient.setRemotePort(port); while (true) { monitor.subTask(Messages.FTPSConnectionFileManager_Connecting); connectFTPSClient(ftpsClient); if (!ftpsClient.isImplicitFTPS()) { final String[] supportedMechanisms = new String[] { SSLFTPClient.AUTH_TLS, SSLFTPClient.AUTH_TLS_C, SSLFTPClient.AUTH_SSL }; boolean supportsPBSZ = true; boolean supportsPROT = true; try { String[] features = ftpClient.features(); if (features != null && features.length > 0) { for (int i = 0; i < features.length; ++i) { features[i] = features[i].trim(); } List<String> featuresList = Arrays.asList(features); for (int i = 0; i < supportedMechanisms.length; ++i) { if (securityMechanism == null && featuresList.contains("AUTH " + supportedMechanisms[i])) { //$NON-NLS-1$ securityMechanism = supportedMechanisms[i]; break; } } supportsPBSZ = featuresList.contains("PBSZ"); //$NON-NLS-1$ supportsPROT = featuresList.contains("PROT"); //$NON-NLS-1$ } } catch (Exception e) { e.getCause(); } if (securityMechanism != null) { ftpsClient.auth(securityMechanism); } else { // server didn't indicate its supported auth mechanism, try them one-by-one for (String auth : supportedMechanisms) { try { ftpsClient.auth(auth); securityMechanism = auth; break; } catch (SSLFTPCertificateException e) { throw e; } catch (FTPException e) { e.getCause(); } } } try { if (supportsPBSZ) { ftpsClient.pbsz(0); } if (supportsPROT) { ftpsClient.prot(SSLFTPClient.PROT_PRIVATE); } } catch (SSLFTPCertificateException e) { throw e; } catch (FTPException e) { if (supportsPROT) { ftpsClient.prot(SSLFTPClient.PROT_CLEAR); } } } if (password.length == 0 && !IFTPConstants.LOGIN_ANONYMOUS.equals(login) && (context == null || !context.getBoolean(ConnectionContext.NO_PASSWORD_PROMPT))) { getOrPromptPassword(MessageFormat.format(Messages.FTPSConnectionFileManager_FTPSAuthentication, host), Messages.FTPSConnectionFileManager_SpecifyPassword); } Policy.checkCanceled(monitor); monitor.subTask(Messages.FTPSConnectionFileManager_Authenticating); try { ftpClient.login(login, String.copyValueOf(password)); } catch (FTPException e) { Policy.checkCanceled(monitor); if ("331".equals(ftpClient.getLastValidReply().getReplyCode())) { //$NON-NLS-1$ if (context != null && context.getBoolean(ConnectionContext.NO_PASSWORD_PROMPT)) { throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID, MessageFormat.format(Messages.FTPSConnectionFileManager_FailedAuthenticate, e.getLocalizedMessage()), e)); } promptPassword(MessageFormat.format(Messages.FTPSConnectionFileManager_FTPSAuthentication, host), Messages.FTPSConnectionFileManager_PasswordNotAccepted); safeQuit(); continue; } throw e; } break; } Policy.checkCanceled(monitor); if (ftpsClient.isImplicitFTPS()) { ftpsClient.auth(SSLFTPClient.PROT_PRIVATE); } Policy.checkCanceled(monitor); changeCurrentDir(basePath); ftpClient.setType(IFTPConstants.TRANSFER_TYPE_ASCII.equals(transferType) ? FTPTransferType.ASCII : FTPTransferType.BINARY); if ((hasServerInfo || (context != null && context.getBoolean(ConnectionContext.QUICK_CONNECT))) && !(context != null && context.getBoolean(ConnectionContext.DETECT_TIMEZONE))) { return; } getherServerInfo(context, monitor); } catch (OperationCanceledException e) { safeQuit(); throw e; } catch (CoreException e) { safeQuit(); throw e; } catch (UnknownHostException e) { safeQuit(); throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID, Messages.FTPSConnectionFileManager_HostNameNotFound+e.getLocalizedMessage(), e)); } catch (SSLFTPCertificateException e) { safeQuit(); throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID, Messages.FTPSConnectionFileManager_ServerSertificateError+e.getLocalizedMessage(), e)); } catch (FileNotFoundException e) { safeQuit(); throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID, Messages.FTPSConnectionFileManager_RemoteFolderNotFound+e.getLocalizedMessage(), e)); } catch (Exception e) { safeQuit(); throw new CoreException(new Status(Status.ERROR, SecureFTPPlugin.PLUGIN_ID, Messages.FTPSConnectionFileManager_FailedEstablishConnection+e.getLocalizedMessage(), e)); } finally { monitor.done(); } } /* * (non-Javadoc) * @see com.aptana.filesystem.ftp.internal.FTPConnectionFileManager#newClient() */ @Override public FTPClient newClient() { try { return new SSLFTPClient(); } catch (FTPException e) { SecureFTPPlugin.log(new Status(IStatus.ERROR, SecureFTPPlugin.PLUGIN_ID, "", e)); //$NON-NLS-1$ } return null; } private static void connectFTPSClient(FTPClient ftpClient) throws IOException, FTPException { PerformanceStats stats = PerformanceStats.getStats("com.aptana.filesystem.ftp/perf/connect", FTPSConnectionFileManager.class.getName()); //$NON-NLS-1$ stats.startRun(ftpClient.getRemoteHost()); try { ftpClient.connect(); } finally { stats.endRun(); } } /* (non-Javadoc) * @see com.aptana.filesystem.secureftp.FTPConnectionFileManager#initAndAuthFTPClient(com.enterprisedt.net.ftp.FTPClient, org.eclipse.core.runtime.IProgressMonitor) */ @Override public void initAndAuthFTPClient(FTPClientInterface newFtpClient, IProgressMonitor monitor) throws IOException, FTPException { if (newFtpClient.connected()) { return; } SSLFTPClient newFtpsClient = (SSLFTPClient) newFtpClient; initFTPSClient(newFtpsClient, !((SSLFTPClient) ftpClient).isImplicitFTPS(), FTPConnectMode.PASV.equals(ftpClient.getConnectMode()), ftpClient.getControlEncoding(), validateCertificate, noSSLSessionResumption); newFtpClient.setRemoteHost(host); newFtpClient.setRemotePort(port); Policy.checkCanceled(monitor); connectFTPSClient(newFtpsClient); monitor.worked(1); Policy.checkCanceled(monitor); if (!newFtpsClient.isImplicitFTPS()) { newFtpsClient.auth(securityMechanism); } try { if (serverSupportsFeature("PBSZ")) { //$NON-NLS-1$ newFtpsClient.pbsz(0); } if (serverSupportsFeature("PROT")) { //$NON-NLS-1$ newFtpsClient.prot(SSLFTPClient.PROT_PRIVATE); } } catch (FTPException e) { if (serverSupportsFeature("PROT")) { //$NON-NLS-1$ newFtpsClient.prot(SSLFTPClient.PROT_CLEAR); } } newFtpsClient.login(login, String.copyValueOf(password)); monitor.worked(1); } /* (non-Javadoc) * @see com.aptana.filesystem.secureftp.FTPConnectionFileManager#getRootCanonicalURI() */ @Override protected URI getRootCanonicalURI() { try { return new URI("ftps", login, host, (port != IFTPSConstants.FTP_PORT_DEFAULT && port != IFTPSConstants.FTPS_IMPLICIT_PORT) ? port : -1, Path.ROOT.toPortableString(), null, null); //$NON-NLS-1$ } catch (URISyntaxException e) { return null; } } }