| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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.apache.airavata.mft.transport.scp; |
| |
| import net.schmizz.sshj.SSHClient; |
| import net.schmizz.sshj.sftp.FileAttributes; |
| import net.schmizz.sshj.sftp.FileMode; |
| import net.schmizz.sshj.sftp.RemoteResourceInfo; |
| import net.schmizz.sshj.sftp.SFTPClient; |
| import net.schmizz.sshj.transport.verification.HostKeyVerifier; |
| import net.schmizz.sshj.userauth.keyprovider.KeyProvider; |
| import net.schmizz.sshj.userauth.method.AuthKeyboardInteractive; |
| import net.schmizz.sshj.userauth.method.AuthMethod; |
| import net.schmizz.sshj.userauth.method.AuthPublickey; |
| import net.schmizz.sshj.userauth.method.ChallengeResponseProvider; |
| import net.schmizz.sshj.userauth.password.Resource; |
| import org.apache.airavata.mft.agent.stub.*; |
| import org.apache.airavata.mft.core.api.MetadataCollector; |
| import org.apache.airavata.mft.credential.stubs.scp.SCPSecret; |
| import org.apache.airavata.mft.resource.stubs.scp.storage.SCPStorage; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.io.*; |
| import java.nio.file.Files; |
| import java.security.PublicKey; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| public class SCPMetadataCollector implements MetadataCollector { |
| |
| private static final Logger logger = LoggerFactory.getLogger(SCPMetadataCollector.class); |
| |
| boolean initialized = false; |
| private SCPStorage scpStorage; |
| private SCPSecret scpSecret; |
| |
| @Override |
| public void init(StorageWrapper storage, SecretWrapper secret) { |
| this.scpStorage = storage.getScp(); |
| this.scpSecret = secret.getScp(); |
| this.initialized = true; |
| } |
| |
| @Override |
| public ResourceMetadata getResourceMetadata(String resourcePath, boolean recursiveSearch) throws Exception { |
| |
| ResourceMetadata.Builder resourceBuilder = ResourceMetadata.newBuilder(); |
| try (SSHClient sshClient = getSSHClient(scpStorage, scpSecret)) { |
| try (SFTPClient sftpClient = sshClient.newSFTPClient()) { |
| |
| if (sftpClient.statExistence(resourcePath) == null) { |
| resourceBuilder.setError(MetadataFetchError.NOT_FOUND); |
| return resourceBuilder.build(); |
| } |
| |
| FileAttributes lstat = sftpClient.lstat(resourcePath); |
| |
| |
| if (lstat.getType() == FileMode.Type.REGULAR) { |
| FileMetadata.Builder fileBuilder = FileMetadata.newBuilder(); |
| fileBuilder.setResourceSize(lstat.getSize()); |
| fileBuilder.setCreatedTime(lstat.getAtime()); |
| fileBuilder.setUpdateTime(lstat.getMtime()); |
| fileBuilder.setFriendlyName(new File(resourcePath).getName()); |
| fileBuilder.setResourcePath(resourcePath); |
| resourceBuilder.setFile(fileBuilder); |
| } else if (lstat.getType() == FileMode.Type.DIRECTORY) { |
| |
| DirectoryMetadata.Builder dirBuilder = DirectoryMetadata.newBuilder(); |
| dirBuilder.setResourcePath(resourcePath); |
| dirBuilder.setFriendlyName(new File(resourcePath).getName()); |
| dirBuilder.setUpdateTime(lstat.getMtime()); |
| dirBuilder.setCreatedTime(lstat.getAtime()); |
| |
| List<RemoteResourceInfo> dirList = sftpClient.ls(resourcePath); |
| for (RemoteResourceInfo rr: dirList) { |
| if (rr.isDirectory()) { |
| DirectoryMetadata.Builder subDir = DirectoryMetadata.newBuilder(); |
| subDir.setResourcePath(rr.getPath()); |
| subDir.setFriendlyName(rr.getName()); |
| subDir.setCreatedTime(rr.getAttributes().getAtime()); |
| subDir.setUpdateTime(rr.getAttributes().getMtime()); |
| dirBuilder.addDirectories(subDir); |
| } else { |
| FileMetadata.Builder fileBuilder = FileMetadata.newBuilder(); |
| fileBuilder.setResourceSize(rr.getAttributes().getSize()); |
| fileBuilder.setCreatedTime(rr.getAttributes().getAtime()); |
| fileBuilder.setUpdateTime(rr.getAttributes().getMtime()); |
| fileBuilder.setFriendlyName(rr.getName()); |
| fileBuilder.setResourcePath(rr.getPath()); |
| dirBuilder.addFiles(fileBuilder); |
| } |
| } |
| resourceBuilder.setDirectory(dirBuilder); |
| |
| } else { |
| resourceBuilder.setError(MetadataFetchError.UNRECOGNIZED); |
| } |
| } |
| } |
| |
| return resourceBuilder.build(); |
| } |
| |
| private void checkInitialized() { |
| if (!initialized) { |
| throw new IllegalStateException("SCP Metadata Collector is not initialized"); |
| } |
| } |
| |
| @Override |
| public Boolean isAvailable(String resourcePath) throws Exception { |
| |
| checkInitialized(); |
| |
| try (SSHClient sshClient = getSSHClient(scpStorage, scpSecret)) { |
| logger.info("Checking the availability of file {}", resourcePath); |
| try (SFTPClient sftpClient = sshClient.newSFTPClient()) { |
| return sftpClient.statExistence(resourcePath) != null; |
| } |
| } |
| } |
| |
| private SSHClient getSSHClient(SCPStorage scpStorage, SCPSecret scpSecret) throws IOException { |
| |
| SSHClient sshClient = new SSHClient(); |
| |
| HostKeyVerifier hkv = new HostKeyVerifier() { |
| @Override |
| public boolean verify(String s, int i, PublicKey publicKey) { |
| return true; |
| } |
| |
| @Override |
| public List<String> findExistingAlgorithms(String hostname, int port) { |
| return Collections.emptyList(); |
| } |
| }; |
| |
| sshClient.addHostKeyVerifier(hkv); |
| |
| File privateKeyFile = Files.createTempFile("id_rsa", "").toFile(); |
| BufferedWriter writer = new BufferedWriter(new FileWriter(privateKeyFile)); |
| writer.write(scpSecret.getPrivateKey()); |
| writer.close(); |
| |
| KeyProvider keyProvider = sshClient.loadKeys(privateKeyFile.getPath(), scpSecret.getPassphrase()); |
| final List<AuthMethod> am = new LinkedList<>(); |
| am.add(new AuthPublickey(keyProvider)); |
| am.add(new AuthKeyboardInteractive(new ChallengeResponseProvider() { |
| @Override |
| public List<String> getSubmethods() { |
| return new ArrayList<>(); |
| } |
| |
| @Override |
| public void init(Resource resource, String name, String instruction) {} |
| |
| @Override |
| public char[] getResponse(String prompt, boolean echo) { |
| return new char[0]; |
| } |
| |
| @Override |
| public boolean shouldRetry() { |
| return false; |
| } |
| })); |
| |
| sshClient.connect(scpStorage.getHost(), scpStorage.getPort()); |
| sshClient.auth(scpSecret.getUser(), am); |
| |
| return sshClient; |
| } |
| } |