org.pentaho.di.core.vfs.SftpFileSystemWindows.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.di.core.vfs.SftpFileSystemWindows.java

Source

/*! ******************************************************************************
 *
 * Pentaho Data Integration
 *
 * Copyright (C) 2002-2017 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;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.UserAuthenticationData;
import org.apache.commons.vfs2.provider.GenericFileName;
import org.apache.commons.vfs2.provider.sftp.SftpClientFactory;
import org.apache.commons.vfs2.provider.sftp.SftpFileProvider;
import org.apache.commons.vfs2.provider.sftp.SftpFileSystem;
import org.apache.commons.vfs2.util.UserAuthenticatorUtils;
import org.pentaho.di.core.logging.LogChannel;
import org.pentaho.di.core.logging.LogChannelInterface;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SftpFileSystemWindows extends SftpFileSystem {

    private static final LogChannelInterface log = new LogChannel("SftpFileSystemWindows");
    private static final String WHO_AMI_GROUPS_FO_LIST = "Whoami /GROUPS /FO LIST"; //windows command for getting croups for current user
    private static final String WHO_AMI = "Whoami "; ////windows command for getting current user
    private static final String ICACLS = "icacls "; //windows command for getting permissions for file
    private static final String VER = "ver"; //windows command for getting version OS
    private static final String GROUP_NAME = "Group Name:";
    private static final String WINDOWS = "WINDOWS";
    private static final String N_DELIMITER = "\\n";
    private static final String RN_DELIMITER = "\r\n";
    private static final String WINDOWS_PATH_DELIMITER = "/";

    private Session session;
    private List<String> userGroups;
    private Boolean windows;

    public SftpFileSystemWindows(GenericFileName rootName, Session session, FileSystemOptions fileSystemOptions) {
        super(rootName, session, fileSystemOptions);
        this.session = session;
    }

    /**
     * get user group on remote windows host
     * @return  list of groups + user person
     * @throws JSchException
     * @throws IOException
     */
    public List<String> getUserGroups() throws JSchException, IOException {
        if (userGroups == null) {
            StringBuilder output = new StringBuilder();
            int code = this.executeCommand(WHO_AMI_GROUPS_FO_LIST, output);
            if (code != 0) {
                throw new JSchException("Could not get the groups  of the current user (error code: " + code + ")");
            }

            this.userGroups = getUserGroups(output.toString());
            userGroups.add(getUser());
        }
        return this.userGroups;
    }

    /**
     * cut user groups from output whoami
     *
     * @param commandOutput output from whoami
     * @return list of user groups
     */
    private List<String> getUserGroups(String commandOutput) {
        List<String> result = new ArrayList<>();
        int startIndex = 0;
        int endIndex;
        while (true) {

            startIndex = StringUtils.indexOfIgnoreCase(commandOutput, GROUP_NAME, startIndex);
            if (startIndex < 0) {
                return result;
            }
            startIndex += GROUP_NAME.length();
            endIndex = StringUtils.indexOfIgnoreCase(commandOutput, RN_DELIMITER, startIndex);
            if (endIndex < 0) {
                return result;
            }
            result.add(commandOutput.substring(startIndex, endIndex).toUpperCase().trim());
        }
    }

    /**
     * Get current user on remote host
     *
     * @return name of user on remote host
     * @throws JSchException
     * @throws IOException
     */
    public String getUser() throws JSchException, IOException {
        StringBuilder output = new StringBuilder();
        int code = this.executeCommand(WHO_AMI, output);
        if (code != 0) {
            throw new JSchException("Could not get user name on remote host (error code: " + code + ")");
        }

        return output.toString().trim().toUpperCase();
    }

    /**
     *
     * @param path path to file or directory
     *
     * @return Map Windows Group - permissions
     * @throws JSchException
     * @throws IOException
     */
    public Map<String, String> getFilePermission(String path) throws JSchException, IOException {
        String windowsAbsPath;
        if (path.startsWith(WINDOWS_PATH_DELIMITER)) {
            //cut first "/" windows does not have it
            //it mean first letter is name of disk
            path = path.substring(WINDOWS_PATH_DELIMITER.length());
            windowsAbsPath = path.substring(0, 1) + ":" + path.substring(1);
        } else {
            windowsAbsPath = path;
        }
        Map<String, String> result = new HashMap<>();
        StringBuilder output = new StringBuilder();
        int code = this.executeCommand(ICACLS + windowsAbsPath, output);
        if (code != 0) {
            return result;
        }
        String outputString = output.toString();

        int indexOf = outputString.indexOf(windowsAbsPath);
        if (indexOf > -1) {
            outputString = outputString.substring(indexOf + windowsAbsPath.length());
        }

        String[] strings = outputString.toUpperCase().split(N_DELIMITER);
        for (String string : strings) {
            int index = string.indexOf(":");
            if (index > -1) {
                result.put(string.substring(0, index).trim(), string.substring(index + 1).trim());
            }
        }
        return result;
    }

    /**
     * check is remote host is windows
     *
     * @return true if host windows
     * @throws JSchException
     * @throws IOException
     */
    public boolean isRemoteHostWindows() throws JSchException, IOException {
        if (this.windows == null) {
            StringBuilder output = new StringBuilder();
            int code = this.executeCommand(VER, output);
            this.windows = code == 0 && output.toString().toUpperCase().contains(WINDOWS);
        }
        return this.windows;
    }

    /**
     * {@link  org.apache.commons.vfs2.provider.sftp.SftpFileSystem#getChannel() }
     *
     */
    private void ensureSession() throws FileSystemException {
        if (this.session == null || !this.session.isConnected()) {
            this.doCloseCommunicationLink();
            UserAuthenticationData authData = null;

            Session session;
            try {
                GenericFileName e = (GenericFileName) this.getRootName();
                authData = UserAuthenticatorUtils.authenticate(this.getFileSystemOptions(),
                        SftpFileProvider.AUTHENTICATOR_TYPES);
                session = SftpClientFactory.createConnection(e.getHostName(), e.getPort(),
                        UserAuthenticatorUtils.getData(authData, UserAuthenticationData.USERNAME,
                                UserAuthenticatorUtils.toChar(e.getUserName())),
                        UserAuthenticatorUtils.getData(authData, UserAuthenticationData.PASSWORD,
                                UserAuthenticatorUtils.toChar(e.getPassword())),
                        this.getFileSystemOptions());
            } catch (Exception var7) {
                throw new FileSystemException("vfs.provider.sftp/connect.error", this.getRootName(), var7);
            } finally {
                UserAuthenticatorUtils.cleanup(authData);
            }

            this.session = session;
        }

    }

    /**
     *
     * {@link  org.apache.commons.vfs2.provider.sftp.SftpFileSystem#executeCommand(java.lang.String, java.lang.StringBuilder) }
     */
    private int executeCommand(String command, StringBuilder output) throws JSchException, IOException {
        this.ensureSession();
        ChannelExec channel = (ChannelExec) this.session.openChannel("exec");
        channel.setCommand(command);
        channel.setInputStream((InputStream) null);
        InputStreamReader stream = new InputStreamReader(channel.getInputStream());
        channel.setErrStream(System.err, true);
        channel.connect();
        char[] buffer = new char[128];

        int read;
        while ((read = stream.read(buffer, 0, buffer.length)) >= 0) {
            output.append(buffer, 0, read);
        }

        stream.close();

        while (!channel.isClosed()) {
            try {
                Thread.sleep(100L);
            } catch (Exception exc) {
                log.logMinimal("Warning: Error session closing. " + exc.getMessage());
            }
        }

        channel.disconnect();
        return channel.getExitStatus();
    }
}