001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.vfs2.provider.sftp;
018
019import java.io.File;
020import java.io.Serializable;
021
022import org.apache.commons.vfs2.FileSystem;
023import org.apache.commons.vfs2.FileSystemConfigBuilder;
024import org.apache.commons.vfs2.FileSystemException;
025import org.apache.commons.vfs2.FileSystemOptions;
026
027import com.jcraft.jsch.UserInfo;
028
029/**
030 * The config builder for various SFTP configuration options.
031 */
032public final class SftpFileSystemConfigBuilder extends FileSystemConfigBuilder {
033    /**
034     * Proxy type.
035     */
036    public static final class ProxyType implements Serializable, Comparable<ProxyType> {
037        /**
038         * serialVersionUID format is YYYYMMDD for the date of the last binary change.
039         */
040        private static final long serialVersionUID = 20101208L;
041
042        private final String proxyType;
043
044        private ProxyType(final String proxyType) {
045            this.proxyType = proxyType;
046        }
047
048        @Override
049        public int compareTo(final ProxyType pType) {
050            return this.proxyType.compareTo(pType.proxyType);
051        }
052
053        @Override
054        public boolean equals(final Object obj) {
055            if (this == obj) {
056                return true;
057            }
058            if (obj == null || this.getClass() != obj.getClass()) {
059                return false;
060            }
061
062            final ProxyType pType = (ProxyType) obj;
063
064            if (this.proxyType != null ? !this.proxyType.equals(pType.proxyType) : pType.proxyType != null) {
065                return false;
066            }
067
068            return true;
069        }
070
071        /**
072         * @return a hash code value for this object.
073         * @since 2.0
074         */
075        @Override
076        public int hashCode() {
077            return this.proxyType.hashCode();
078        }
079    }
080
081    /** HTTP Proxy. */
082    public static final ProxyType PROXY_HTTP = new ProxyType("http");
083
084    /** SOCKS Proxy. */
085    public static final ProxyType PROXY_SOCKS5 = new ProxyType("socks");
086
087    /**
088     * Connects to the SFTP server through a remote host reached by SSH.
089     * <p>
090     * On this proxy host, a command (e.g. {@linkplain SftpStreamProxy#NETCAT_COMMAND} or
091     * {@linkplain SftpStreamProxy#NETCAT_COMMAND}) is run to forward input/output streams between the target host and
092     * the VFS host.
093     * <p>
094     * When used, the proxy username ({@linkplain #setProxyUser}) and hostname ({@linkplain #setProxyHost}) <b>must</b>
095     * be set. Optionnaly, the command ({@linkplain #setProxyCommand}), password ({@linkplain #setProxyPassword}) and
096     * connection options ({@linkplain #setProxyOptions}) can be set.
097     */
098    public static final ProxyType PROXY_STREAM = new ProxyType("stream");
099
100    private static final String _PREFIX = SftpFileSystemConfigBuilder.class.getName();
101    private static final SftpFileSystemConfigBuilder BUILDER = new SftpFileSystemConfigBuilder();
102    private static final String COMPRESSION = _PREFIX + "COMPRESSION";
103    private static final String HOST_KEY_CHECK_ASK = "ask";
104    private static final String HOST_KEY_CHECK_NO = "no";
105    private static final String HOST_KEY_CHECK_YES = "yes";
106    private static final String IDENTITIES = _PREFIX + ".IDENTITIES";
107    private static final String IDENTITY_REPOSITORY_FACTORY = _PREFIX + "IDENTITY_REPOSITORY_FACTORY";
108    private static final String KNOWN_HOSTS = _PREFIX + ".KNOWN_HOSTS";
109    private static final String PREFERRED_AUTHENTICATIONS = _PREFIX + ".PREFERRED_AUTHENTICATIONS";
110
111    private static final String PROXY_HOST = _PREFIX + ".PROXY_HOST";
112    private static final String PROXY_USER = _PREFIX + ".PROXY_USER";
113    private static final String PROXY_OPTIONS = _PREFIX + ".PROXY_OPTIONS";
114    private static final String PROXY_TYPE = _PREFIX + ".PROXY_TYPE";
115    private static final String PROXY_PORT = _PREFIX + ".PROXY_PORT";
116    private static final String PROXY_PASSWORD = _PREFIX + ".PROXY_PASSWORD";
117    private static final String PROXY_COMMAND = _PREFIX + ".PROXY_COMMAND";
118
119    private static final String STRICT_HOST_KEY_CHECKING = _PREFIX + ".STRICT_HOST_KEY_CHECKING";
120    private static final String TIMEOUT = _PREFIX + ".TIMEOUT";
121    private static final String USER_DIR_IS_ROOT = _PREFIX + ".USER_DIR_IS_ROOT";
122    private static final String ENCODING = _PREFIX + ".ENCODING";
123
124    private SftpFileSystemConfigBuilder() {
125        super("sftp.");
126    }
127
128    /**
129     * Gets the singleton builder.
130     *
131     * @return the singleton builder.
132     */
133    public static SftpFileSystemConfigBuilder getInstance() {
134        return BUILDER;
135    }
136
137    /**
138     * @param opts The FileSystem options.
139     * @return The names of the compression algorithms, comma-separated.
140     * @see #setCompression
141     */
142    public String getCompression(final FileSystemOptions opts) {
143        return this.getString(opts, COMPRESSION);
144    }
145
146    @Override
147    protected Class<? extends FileSystem> getConfigClass() {
148        return SftpFileSystem.class;
149    }
150
151    /**
152     * Gets the file name encoding.
153     *
154     * @param opts The FileSystem options.
155     * @return the file name encoding
156     */
157    public String getFileNameEncoding(final FileSystemOptions opts) {
158        return this.getString(opts, ENCODING);
159    }
160
161    /**
162     * Gets the identity files (your private key files).
163     * <p>
164     * We use java.io.File because JSch cannot deal with VFS FileObjects.
165     *
166     * @param opts The FileSystem options.
167     * @return the array of identity Files.
168     * @see #setIdentities
169     * @deprecated As of 2.1 use {@link #getIdentityInfo(FileSystemOptions)}
170     */
171    @Deprecated
172    public File[] getIdentities(final FileSystemOptions opts) {
173        final IdentityInfo[] info = getIdentityInfo(opts);
174        if (info != null) {
175            final File[] files = new File[info.length];
176            for (int i = 0; i < files.length; ++i) {
177                files[i] = info[i].getPrivateKey();
178            }
179            return files;
180        }
181        return null;
182    }
183
184    /**
185     * Gets the identity info.
186     *
187     * @param opts The FileSystem options.
188     * @return the array of identity info instances.
189     * @see #setIdentityInfo
190     */
191    public IdentityInfo[] getIdentityInfo(final FileSystemOptions opts) {
192        return (IdentityInfo[]) this.getParam(opts, IDENTITIES);
193    }
194
195    /**
196     * Get the identity repository factory.
197     *
198     * @param opts The FileSystem options.
199     * @return the IdentityRepositoryFactory
200     */
201    public IdentityRepositoryFactory getIdentityRepositoryFactory(final FileSystemOptions opts) {
202        return (IdentityRepositoryFactory) this.getParam(opts, IDENTITY_REPOSITORY_FACTORY);
203    }
204
205    /**
206     * @param opts The FileSystem options.
207     * @return the known hosts File.
208     * @see #setKnownHosts
209     */
210    public File getKnownHosts(final FileSystemOptions opts) {
211        return (File) this.getParam(opts, KNOWN_HOSTS);
212    }
213
214    /**
215     * Gets authentication order.
216     *
217     * @param opts The FileSystem options.
218     * @return The authentication order.
219     * @since 2.0
220     */
221    public String getPreferredAuthentications(final FileSystemOptions opts) {
222        return getString(opts, PREFERRED_AUTHENTICATIONS);
223    }
224
225    /**
226     * Gets the command that will be run on the proxy host when using a {@linkplain SftpStreamProxy}. The command
227     * defaults to {@linkplain SftpStreamProxy#NETCAT_COMMAND}.
228     *
229     * @param opts The FileSystem options.
230     * @return proxyOptions
231     * @see SftpStreamProxy
232     * @see #setProxyOptions
233     * @since 2.1
234     */
235    public String getProxyCommand(final FileSystemOptions opts) {
236        return this.getString(opts, PROXY_COMMAND, SftpStreamProxy.NETCAT_COMMAND);
237    }
238
239    /**
240     * Gets the proxy to use for the SFTP connection.
241     *
242     * @param opts The FileSystem options.
243     * @return proxyHost
244     * @see #getProxyPort
245     * @see #setProxyHost
246     */
247    public String getProxyHost(final FileSystemOptions opts) {
248        return this.getString(opts, PROXY_HOST);
249    }
250
251    /**
252     * Gets the proxy options that are used to connect to the proxy host.
253     *
254     * @param opts The FileSystem options.
255     * @return proxyOptions
256     * @see SftpStreamProxy
257     * @see #setProxyOptions
258     * @since 2.1
259     */
260    public FileSystemOptions getProxyOptions(final FileSystemOptions opts) {
261        return (FileSystemOptions) this.getParam(opts, PROXY_OPTIONS);
262    }
263
264    /**
265     * Gets the proxy password that are used to connect to the proxy host.
266     *
267     * @param opts The FileSystem options.
268     * @return proxyOptions
269     * @see SftpStreamProxy
270     * @see #setProxyPassword
271     * @since 2.1
272     */
273    public String getProxyPassword(final FileSystemOptions opts) {
274        return this.getString(opts, PROXY_PASSWORD);
275    }
276
277    /**
278     * Gets the proxy-port to use for the SFTP the connection.
279     *
280     * @param opts The FileSystem options.
281     * @return proxyPort: the port number or 0 if it is not set
282     * @see #setProxyPort
283     * @see #getProxyHost
284     */
285    public int getProxyPort(final FileSystemOptions opts) {
286        return this.getInteger(opts, PROXY_PORT, 0);
287    }
288
289    /**
290     * Gets the proxy type to use for the SFTP connection.
291     *
292     * @param opts The FileSystem options.
293     * @return The ProxyType.
294     */
295    public ProxyType getProxyType(final FileSystemOptions opts) {
296        return (ProxyType) this.getParam(opts, PROXY_TYPE);
297    }
298
299    /**
300     * Gets the user name for the proxy used for the SFTP connection.
301     *
302     * @param opts The FileSystem options.
303     * @return proxyUser
304     * @see #setProxyUser
305     * @since 2.1
306     */
307    public String getProxyUser(final FileSystemOptions opts) {
308        return this.getString(opts, PROXY_USER);
309    }
310
311    /**
312     * @param opts The FileSystem options.
313     * @return the option value The host key checking.
314     * @see #setStrictHostKeyChecking(FileSystemOptions, String)
315     */
316    public String getStrictHostKeyChecking(final FileSystemOptions opts) {
317        return this.getString(opts, STRICT_HOST_KEY_CHECKING, HOST_KEY_CHECK_NO);
318    }
319
320    /**
321     * @param opts The FileSystem options.
322     * @return The timeout value in milliseconds.
323     * @see #setTimeout
324     */
325    public Integer getTimeout(final FileSystemOptions opts) {
326        return this.getInteger(opts, TIMEOUT);
327    }
328
329    /**
330     * Returns {@link Boolean#TRUE} if VFS should treat the user directory as the root directory. Defaults to
331     * <code>Boolean.TRUE</code> if the method {@link #setUserDirIsRoot(FileSystemOptions, boolean)} has not been
332     * invoked.
333     *
334     * @param opts The FileSystemOptions.
335     * @return <code>Boolean.TRUE</code> if VFS treats the user directory as the root directory.
336     * @see #setUserDirIsRoot
337     */
338    public Boolean getUserDirIsRoot(final FileSystemOptions opts) {
339        return this.getBoolean(opts, USER_DIR_IS_ROOT, Boolean.TRUE);
340    }
341
342    /**
343     * @param opts The FileSystem options.
344     * @return The UserInfo.
345     * @see #setUserInfo
346     */
347    public UserInfo getUserInfo(final FileSystemOptions opts) {
348        return (UserInfo) this.getParam(opts, UserInfo.class.getName());
349    }
350
351    /**
352     * Configures the compression algorithms to use.
353     * <p>
354     * For example, use {@code "zlib,none"} to enable compression.
355     * <p>
356     * See the Jsch documentation (in particular the README file) for details.
357     *
358     * @param opts The FileSystem options.
359     * @param compression The names of the compression algorithms, comma-separated.
360     * @throws FileSystemException if an error occurs.
361     */
362    public void setCompression(final FileSystemOptions opts, final String compression) throws FileSystemException {
363        this.setParam(opts, COMPRESSION, compression);
364    }
365
366    /**
367     * Sets the file name encoding.
368     *
369     * @param opts The FileSystem options.
370     * @param fileNameEncoding The name of the encoding to use for file names.
371     */
372    public void setFileNameEncoding(final FileSystemOptions opts, final String fileNameEncoding) {
373        this.setParam(opts, ENCODING, fileNameEncoding);
374    }
375
376    /**
377     * Sets the identity files (your private key files).
378     * <p>
379     * We use {@link java.io.File} because JSch cannot deal with VFS FileObjects.
380     *
381     * @param opts The FileSystem options.
382     * @param identityFiles An array of identity Files.
383     * @throws FileSystemException if an error occurs.
384     * @deprecated As of 2.1 use {@link #setIdentityInfo(FileSystemOptions, IdentityInfo...)}
385     */
386    @Deprecated
387    public void setIdentities(final FileSystemOptions opts, final File... identityFiles) throws FileSystemException {
388        IdentityInfo[] info = null;
389        if (identityFiles != null) {
390            info = new IdentityInfo[identityFiles.length];
391            for (int i = 0; i < identityFiles.length; i++) {
392                info[i] = new IdentityInfo(identityFiles[i]);
393            }
394        }
395        this.setParam(opts, IDENTITIES, info);
396    }
397
398    /**
399     * Sets the identity info (your private key files).
400     *
401     * @param opts The FileSystem options.
402     * @param identites An array of identity info.
403     * @throws FileSystemException if an error occurs.
404     * @since 2.1
405     */
406    public void setIdentityInfo(final FileSystemOptions opts, final IdentityInfo... identites)
407            throws FileSystemException {
408        this.setParam(opts, IDENTITIES, identites);
409    }
410
411    /**
412     * Set the identity repository.
413     * <p>
414     * This is useful when you want to use e.g. an SSH agent as provided.
415     *
416     * @param opts The FileSystem options.
417     * @param factory An identity repository.
418     * @throws FileSystemException if an error occurs.
419     * @see <a href="http://www.jcraft.com/jsch-agent-proxy/">JSch agent proxy</a>
420     */
421    public void setIdentityRepositoryFactory(final FileSystemOptions opts, final IdentityRepositoryFactory factory)
422            throws FileSystemException {
423        this.setParam(opts, IDENTITY_REPOSITORY_FACTORY, factory);
424    }
425
426    /**
427     * Sets the known_hosts file. e.g. {@code /home/user/.ssh/known_hosts2}.
428     * <p>
429     * We use {@link java.io.File} because JSch cannot deal with VFS FileObjects.
430     *
431     * @param opts The FileSystem options.
432     * @param knownHosts The known hosts file.
433     * @throws FileSystemException if an error occurs.
434     */
435    public void setKnownHosts(final FileSystemOptions opts, final File knownHosts) throws FileSystemException {
436        this.setParam(opts, KNOWN_HOSTS, knownHosts);
437    }
438
439    /**
440     * Configures authentication order.
441     *
442     * @param opts The FileSystem options.
443     * @param preferredAuthentications The authentication order.
444     * @since 2.0
445     */
446    public void setPreferredAuthentications(final FileSystemOptions opts, final String preferredAuthentications) {
447        this.setParam(opts, PREFERRED_AUTHENTICATIONS, preferredAuthentications);
448    }
449
450    /**
451     * Sets the proxy username to use for the SFTP connection.
452     *
453     * @param opts The FileSystem options.
454     * @param proxyCommand the port
455     * @see #getProxyOptions
456     * @since 2.1
457     */
458    public void setProxyCommand(final FileSystemOptions opts, final String proxyCommand) {
459        this.setParam(opts, PROXY_COMMAND, proxyCommand);
460    }
461
462    /**
463     * Sets the proxy to use for the SFTP connection.
464     *
465     * You MUST also set the proxy port to use the proxy.
466     *
467     * @param opts The FileSystem options.
468     * @param proxyHost the host
469     * @see #setProxyPort
470     */
471    public void setProxyHost(final FileSystemOptions opts, final String proxyHost) {
472        this.setParam(opts, PROXY_HOST, proxyHost);
473    }
474
475    /**
476     * Sets the proxy username to use for the SFTP connection.
477     *
478     * @param opts The FileSystem options.
479     * @param proxyOptions the options
480     * @see #getProxyOptions
481     * @since 2.1
482     */
483    public void setProxyOptions(final FileSystemOptions opts, final FileSystemOptions proxyOptions) {
484        this.setParam(opts, PROXY_OPTIONS, proxyOptions);
485    }
486
487    /**
488     * Sets the proxy password to use for the SFTP connection.
489     *
490     * @param opts The FileSystem options.
491     * @param proxyPassword the username used to connect to the proxy
492     * @see #getProxyPassword
493     * @since 2.1
494     */
495    public void setProxyPassword(final FileSystemOptions opts, final String proxyPassword) {
496        this.setParam(opts, PROXY_PASSWORD, proxyPassword);
497    }
498
499    /**
500     * Sets the proxy port to use for the SFTP connection.
501     * <p>
502     * You MUST also set the proxy host to use the proxy.
503     *
504     * @param opts The FileSystem options.
505     * @param proxyPort the port
506     * @see #setProxyHost
507     */
508    public void setProxyPort(final FileSystemOptions opts, final int proxyPort) {
509        this.setParam(opts, PROXY_PORT, Integer.valueOf(proxyPort));
510    }
511
512    /**
513     * Sets the proxy type to use for the SFTP connection.
514     *
515     * The possibles values are:
516     * <ul>
517     * <li>{@linkplain #PROXY_HTTP} connects using an HTTP proxy</li>
518     * <li>{@linkplain #PROXY_SOCKS5} connects using an Socket5 proxy</li>
519     * <li>{@linkplain #PROXY_STREAM} connects through a remote host stream command</li>
520     * </ul>
521     *
522     * @param opts The FileSystem options.
523     * @param proxyType the type of the proxy to use.
524     */
525    public void setProxyType(final FileSystemOptions opts, final ProxyType proxyType) {
526        this.setParam(opts, PROXY_TYPE, proxyType);
527    }
528
529    /**
530     * Sets the proxy username to use for the SFTP connection.
531     *
532     * @param opts The FileSystem options.
533     * @param proxyUser the username used to connect to the proxy
534     * @see #getProxyUser
535     * @since 2.1
536     */
537    public void setProxyUser(final FileSystemOptions opts, final String proxyUser) {
538        this.setParam(opts, PROXY_USER, proxyUser);
539    }
540
541    /**
542     * Configures the host key checking to use.
543     * <p>
544     * Valid arguments are: {@code "yes"}, {@code "no"} and {@code "ask"}.
545     * </p>
546     * <p>
547     * See the jsch documentation for details.
548     * </p>
549     *
550     * @param opts The FileSystem options.
551     * @param hostKeyChecking The host key checking to use.
552     * @throws FileSystemException if an error occurs.
553     */
554    public void setStrictHostKeyChecking(final FileSystemOptions opts, final String hostKeyChecking)
555            throws FileSystemException {
556        if (hostKeyChecking == null || (!hostKeyChecking.equals(HOST_KEY_CHECK_ASK)
557                && !hostKeyChecking.equals(HOST_KEY_CHECK_NO) && !hostKeyChecking.equals(HOST_KEY_CHECK_YES))) {
558            throw new FileSystemException("vfs.provider.sftp/StrictHostKeyChecking-arg.error", hostKeyChecking);
559        }
560
561        this.setParam(opts, STRICT_HOST_KEY_CHECKING, hostKeyChecking);
562    }
563
564    /**
565     * Sets the timeout value on Jsch session.
566     *
567     * @param opts The FileSystem options.
568     * @param timeout The timeout in milliseconds.
569     */
570    public void setTimeout(final FileSystemOptions opts, final Integer timeout) {
571        this.setParam(opts, TIMEOUT, timeout);
572    }
573
574    /**
575     * Sets the whether to use the user directory as root (do not change to file system root).
576     *
577     * @param opts The FileSystem options.
578     * @param userDirIsRoot true if the user directory is the root directory.
579     */
580    public void setUserDirIsRoot(final FileSystemOptions opts, final boolean userDirIsRoot) {
581        this.setParam(opts, USER_DIR_IS_ROOT, userDirIsRoot ? Boolean.TRUE : Boolean.FALSE);
582    }
583
584    /**
585     * Sets the Jsch UserInfo class to use.
586     *
587     * @param opts The FileSystem options.
588     * @param info User information.
589     */
590    public void setUserInfo(final FileSystemOptions opts, final UserInfo info) {
591        this.setParam(opts, UserInfo.class.getName(), info);
592    }
593}