/** * PODD is an OWL ontology database used for scientific project management * * Copyright (C) 2009-2013 The University Of Queensland * * This program is free software: you can redistribute it and/or modify it under the terms of the * GNU Affero General Public License as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. */ package com.github.podd.impl.data; import java.io.IOException; import net.schmizz.sshj.DefaultConfig; import net.schmizz.sshj.SSHClient; import net.schmizz.sshj.sftp.FileAttributes; import net.schmizz.sshj.sftp.SFTPClient; import org.openrdf.model.Model; import org.openrdf.model.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.github.podd.api.data.PoddDataRepository; import com.github.podd.api.data.SSHFileReference; import com.github.podd.exception.DataReferenceNotSupportedException; import com.github.podd.exception.DataRepositoryIncompleteException; import com.github.podd.ontologies.PODDDATAREPOSITORY; import com.github.podd.utils.PODD; /** * @author kutila * */ public class SSHFileRepositoryImpl extends AbstractPoddDataRepositoryImpl<SSHFileReference> { private static final DefaultConfig DEFAULT_CONFIG = new DefaultConfig(); protected final Logger log = LoggerFactory.getLogger(this.getClass()); public SSHFileRepositoryImpl(final Resource nextDataRepository, final Model model) throws DataRepositoryIncompleteException { super(nextDataRepository, model); // check that the model contains values for protocol, host, port, // fingerprint, username, and // secret final String protocol = model.filter(this.aliasUri, PODD.PODD_DATA_REPOSITORY_PROTOCOL, null).objectString(); final String host = model.filter(this.aliasUri, PODD.PODD_DATA_REPOSITORY_HOST, null).objectString(); final String port = model.filter(this.aliasUri, PODD.PODD_DATA_REPOSITORY_PORT, null).objectString(); final String fingerprint = model.filter(this.aliasUri, PODD.PODD_FILE_REPOSITORY_FINGERPRINT, null).objectString(); final String username = model.filter(this.aliasUri, PODD.PODD_FILE_REPOSITORY_USERNAME, null).objectString(); final String secret = model.filter(this.aliasUri, PODD.PODD_FILE_REPOSITORY_SECRET, null).objectString(); final String privateKey = model.filter(this.aliasUri, PODDDATAREPOSITORY.HAS_DATA_REPOSITORY_PRIVATE_KEY_PATH, null) .objectString(); if(protocol == null || host == null || port == null || fingerprint == null || username == null || (secret == null && privateKey == null)) { throw new DataRepositoryIncompleteException("SSH repository configuration incomplete"); } if(!PoddDataRepository.PROTOCOL_SSH.equalsIgnoreCase(protocol)) { throw new DataRepositoryIncompleteException("Protocol needs to be SSH"); } } @Override public boolean canHandle(final SSHFileReference reference) { if(reference == null) { return false; } // unnecessary as Generics ensure only an SSHFileReference can be passed // in if(!(reference instanceof SSHFileReference)) { return false; } final String aliasFromFileRef = reference.getRepositoryAlias(); if(aliasFromFileRef == null || !this.alias.equalsIgnoreCase(aliasFromFileRef)) { return false; } return true; } @Override public boolean validate(final SSHFileReference dataReference) throws DataReferenceNotSupportedException, IOException { if(!this.canHandle(dataReference)) { throw new DataReferenceNotSupportedException(dataReference, "cannot handle file reference for validation"); } final String host = this.model.filter(this.aliasUri, PODD.PODD_DATA_REPOSITORY_HOST, null).objectString(); final String port = this.model.filter(this.aliasUri, PODD.PODD_DATA_REPOSITORY_PORT, null).objectString(); final String fingerprint = this.model.filter(this.aliasUri, PODD.PODD_FILE_REPOSITORY_FINGERPRINT, null).objectString(); final String username = this.model.filter(this.aliasUri, PODD.PODD_FILE_REPOSITORY_USERNAME, null).objectString(); final String secret = this.model.filter(this.aliasUri, PODD.PODD_FILE_REPOSITORY_SECRET, null).objectString(); int portNo = -1; try { portNo = Integer.parseInt(port); } catch(final NumberFormatException e) { throw new IOException("Port number could not be parsed correctly: " + port); } String fileName = dataReference.getFilename(); final String path = dataReference.getPath(); if(path != null && path.trim().length() > 0) { fileName = path + "/" + fileName; } this.log.info("Validating file reference: " + host + ":" + port + " " + fileName); try (SSHClient sshClient = new SSHClient(SSHFileRepositoryImpl.DEFAULT_CONFIG);) { sshClient.addHostKeyVerifier(fingerprint); sshClient.connect(host, portNo); sshClient.authPassword(username, secret); try (SFTPClient sftp = sshClient.newSFTPClient();) { // check details of a remote file final FileAttributes attribs = sftp.lstat(fileName); if(attribs == null || attribs.getSize() <= 0) { return false; } } catch(final IOException e) { // lstat() throws an IOException if the file does not exist return false; } } return true; } }