/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2016 by Pentaho : http://www.pentaho.com
*
*******************************************************************************
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
package org.pentaho.di.core.vfs.configuration;
import java.io.File;
import java.io.IOException;
import org.apache.commons.vfs2.FileSystem;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.provider.FileNameParser;
import org.apache.commons.vfs2.provider.URLFileName;
import org.apache.commons.vfs2.provider.sftp.IdentityInfo;
import org.apache.commons.vfs2.provider.sftp.SftpFileNameParser;
import org.apache.commons.vfs2.provider.sftp.SftpFileSystem;
import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;
import org.pentaho.di.core.logging.LogChannel;
import org.pentaho.di.core.logging.LogChannelInterface;
import com.jcraft.jsch.UserInfo;
/**
* An SFTP FileSystemConfigBuilder that uses Kettle variables to build SFTP VFS configuration options. Options can be
* specified by host by appending the host name (as it will appear in the VFS URL) to the end of the parameter. (e.g.-
* vfs.sftp.parameter.192.168.1.5)
*
* Overriden parameters are currently:
* <table style="text-align: left;" border="1">
* <tr>
* <th>Parameter</th>
* <th>Description</th>
* </tr>
* <tr>
* <td>AuthKeyPassphrase</td>
* <td>The passphrase that unlocks the private key. (Recommended on a per host basis, unless the passphrase is the same
* for ALL authentication keys)</td>
* </tr>
* <tr>
* <td>identity</td>
* <td>Local file path (Not VFS) to the private key for authentication.</td>
* </tr>
* </table>
*
* @author cboyden
*/
public class KettleSftpFileSystemConfigBuilder extends KettleGenericFileSystemConfigBuilder {
private static final KettleSftpFileSystemConfigBuilder builder = new KettleSftpFileSystemConfigBuilder();
private static final LogChannelInterface log = new LogChannel( "cfgbuilder" );
private static final String IDENTITY_KEY = SftpFileSystemConfigBuilder.class.getName() + ".IDENTITIES";
public static KettleSftpFileSystemConfigBuilder getInstance() {
return builder;
}
protected KettleSftpFileSystemConfigBuilder() {
super();
}
@Override
protected Class<? extends FileSystem> getConfigClass() {
// Return the VFS driver class that will recognize the parameters processed by this component
return SftpFileSystem.class;
}
/**
* Publicly expose a generic way to set parameters
*/
@Override
public void setParameter( FileSystemOptions opts, String name, String value, String fullParameterName,
String vfsUrl ) throws IOException {
if ( !fullParameterName.startsWith( "vfs.sftp" ) ) {
// This is not an SFTP parameter. Delegate to the generic handler
super.setParameter( opts, name, value, fullParameterName, vfsUrl );
} else {
// Check for the presence of a host in the full variable name
try {
// Parse server name from vfsFilename
FileNameParser sftpFilenameParser = SftpFileNameParser.getInstance();
URLFileName file = (URLFileName) sftpFilenameParser.parseUri( null, null, vfsUrl );
if ( !parameterContainsHost( fullParameterName ) || fullParameterName.endsWith( file.getHostName() ) ) {
// Match special cases for parameter names
if ( name.equalsIgnoreCase( "AuthKeyPassphrase" ) ) {
setParam( opts, UserInfo.class.getName(), new PentahoUserInfo( value ) );
} else if ( name.equals( "identity" ) ) {
IdentityInfo[] identities = (IdentityInfo[]) this.getParam( opts, IDENTITY_KEY );
if ( identities == null ) {
identities = new IdentityInfo[] { new IdentityInfo( new File( value ) ) };
} else {
// Copy, in a Java 5 friendly manner, identities into a larger array
IdentityInfo[] temp = new IdentityInfo[identities.length + 1];
System.arraycopy( identities, 0, temp, 0, identities.length );
identities = temp;
identities[identities.length - 1] = new IdentityInfo( new File( value ) );
}
setParam( opts, IDENTITY_KEY, identities );
} else {
super.setParameter( opts, name, value, fullParameterName, vfsUrl );
}
} else {
// No host match found
log.logDebug( "No host match found for: " + fullParameterName );
}
} catch ( IOException e ) {
log.logError( "Failed to set VFS parameter: [" + fullParameterName + "] " + value, e );
}
}
}
private static boolean parameterContainsHost( String parameter ) {
// Test the number of '.' in the file. If there are more then two, then there is a host associated
return parameter.matches( "^(.*\\..*){3,}" ) ? true : false;
}
private static class PentahoUserInfo implements UserInfo {
private String passphrase;
private String password;
public PentahoUserInfo( String passphrase ) {
this.passphrase = passphrase;
}
@Override
public String getPassphrase() {
return passphrase; // Passphrase for the authentication key
}
@Override
public String getPassword() {
return password; // Appears to be unused in this usage
}
@Override
public boolean promptPassphrase( String arg0 ) {
return true;
}
@Override
public boolean promptPassword( String arg0 ) {
return false;
}
@Override
public boolean promptYesNo( String arg0 ) {
return false;
}
@Override
public void showMessage( String arg0 ) {
}
}
}