diff options
| -rw-r--r-- | src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/CoreConstants.java | 1 | ||||
| -rw-r--r-- | src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/LRUCache.java (renamed from src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/LRUCache.java) | 2 | ||||
| -rw-r--r-- | src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/ProcessResult.java | 1 | ||||
| -rw-r--r-- | src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ImageUtil.java | 1 | ||||
| -rw-r--r-- | src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250-LICENSE.txt | 87 | ||||
| -rw-r--r-- | src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250.jar | bin | 0 -> 248915 bytes | |||
| -rw-r--r-- | src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/SshUtil.java | 268 | 
7 files changed, 359 insertions, 1 deletions
diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/CoreConstants.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/CoreConstants.java index 8a1e1f37..b5e25ce7 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/CoreConstants.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/CoreConstants.java @@ -25,6 +25,7 @@ package com.gluster.storage.management.core.constants;  public class CoreConstants {      public static final String NEWLINE = System.getProperty("line.separator");      public static final String FILE_SEPARATOR = System.getProperty("file.separator"); +    public static final String USER_HOME = System.getProperty("user.home");      public static final String ENCODING_UTF8 = "UTF-8";  	public static final String ALL = "ALL";  	public static final String DATE_WITH_TIME_FORMAT = "MM/dd/yyyy HH:mm:ss"; diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/LRUCache.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/LRUCache.java index 3c805ac8..f3c9c72d 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/LRUCache.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/LRUCache.java @@ -18,7 +18,7 @@   * along with this program. If not, see   * <http://www.gnu.org/licenses/>.   */ -package com.gluster.storage.management.gui.utils; +package com.gluster.storage.management.core.utils;  import java.util.LinkedHashMap;  import java.util.Map; diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/ProcessResult.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/ProcessResult.java index 6c8b857d..9d6ddc93 100644 --- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/ProcessResult.java +++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/ProcessResult.java @@ -28,6 +28,7 @@ import javax.xml.bind.annotation.XmlRootElement;  public class ProcessResult {  	public static final int SUCCESS = 0; +	public static final int FAILURE = 1;  	private int exitValue;  	private String output; diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ImageUtil.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ImageUtil.java index efa169de..d5e568b3 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ImageUtil.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ImageUtil.java @@ -24,6 +24,7 @@ import org.eclipse.jface.resource.ImageDescriptor;  import org.eclipse.swt.graphics.Image;  import org.eclipse.ui.plugin.AbstractUIPlugin; +import com.gluster.storage.management.core.utils.LRUCache;  import com.gluster.storage.management.gui.Application;  /** diff --git a/src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250-LICENSE.txt b/src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250-LICENSE.txt new file mode 100644 index 00000000..3eddd42f --- /dev/null +++ b/src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250-LICENSE.txt @@ -0,0 +1,87 @@ +Copyright (c) 2006 - 2010 Christian Plattner. All rights reserved.
 +
 +Redistribution and use in source and binary forms, with or without
 +modification, are permitted provided that the following conditions
 +are met:
 +
 +a.) Redistributions of source code must retain the above copyright
 +    notice, this list of conditions and the following disclaimer.
 +b.) Redistributions in binary form must reproduce the above copyright
 +    notice, this list of conditions and the following disclaimer in the
 +    documentation and/or other materials provided with the distribution.
 +c.) Neither the name of Christian Plattner nor the names of its contributors may
 +    be used to endorse or promote products derived from this software
 +    without specific prior written permission.
 +
 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 +POSSIBILITY OF SUCH DAMAGE.
 +
 +
 +This software includes work that was released under the following license:
 +
 +Copyright (c) 2005 - 2006 Swiss Federal Institute of Technology (ETH Zurich),
 +  Department of Computer Science (http://www.inf.ethz.ch),
 +  Christian Plattner. All rights reserved.
 +
 +Redistribution and use in source and binary forms, with or without
 +modification, are permitted provided that the following conditions
 +are met:
 +
 +a.) Redistributions of source code must retain the above copyright
 +    notice, this list of conditions and the following disclaimer.
 +b.) Redistributions in binary form must reproduce the above copyright
 +    notice, this list of conditions and the following disclaimer in the
 +    documentation and/or other materials provided with the distribution.
 +c.) Neither the name of ETH Zurich nor the names of its contributors may
 +    be used to endorse or promote products derived from this software
 +    without specific prior written permission.
 +
 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 +POSSIBILITY OF SUCH DAMAGE.
 +
 +
 +The Java implementations of the AES, Blowfish and 3DES ciphers have been
 +taken (and slightly modified) from the cryptography package released by
 +"The Legion Of The Bouncy Castle".
 +
 +Their license states the following:
 +
 +Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle
 +(http://www.bouncycastle.org)
 +
 +Permission is hereby granted, free of charge, to any person obtaining a copy
 +of this software and associated documentation files (the "Software"), to deal
 +in the Software without restriction, including without limitation the rights
 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 +copies of the Software, and to permit persons to whom the Software is
 +furnished to do so, subject to the following conditions:
 +
 +The above copyright notice and this permission notice shall be included in
 +all copies or substantial portions of the Software.
 +
 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 +THE SOFTWARE. 
 +
 diff --git a/src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250.jar b/src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250.jar Binary files differnew file mode 100644 index 00000000..c0a9ac7b --- /dev/null +++ b/src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250.jar diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/SshUtil.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/SshUtil.java new file mode 100644 index 00000000..258bdea3 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/SshUtil.java @@ -0,0 +1,268 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com> + * This file is part of Gluster Management Console. + * + * Gluster Management Console 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. + *   + * Gluster Management Console 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.gluster.storage.management.server.utils; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.Date; + +import ch.ethz.ssh2.ChannelCondition; +import ch.ethz.ssh2.Connection; +import ch.ethz.ssh2.Session; +import ch.ethz.ssh2.StreamGobbler; + +import com.gluster.storage.management.core.constants.CoreConstants; +import com.gluster.storage.management.core.exceptions.GlusterRuntimeException; +import com.gluster.storage.management.core.utils.LRUCache; +import com.gluster.storage.management.core.utils.ProcessResult; + +/** + * + */ +public class SshUtil { +	private LRUCache<String, Connection> sshConnCache = new LRUCache<String, Connection>(10); +	private static final File PEM_FILE = new File(CoreConstants.USER_HOME + "/" + ".ssh/id_rsa"); +	// TODO: Make user name configurable +	private static final String USER_NAME = "root"; +	// TODO: Make default password configurable +	private static final String DEFAULT_PASSWORD = "syst3m"; + +	private Connection getConnectionWithPassword(String serverName) { +		Connection conn = createConnection(serverName); +		authenticateWithPassword(conn); +		return conn; +	} + +	private synchronized Connection getConnection(String serverName) { +		Connection conn = sshConnCache.get(serverName); +		if (conn != null) { +			return conn; +		} + +		conn = createConnection(serverName); +		authenticateWithPublicKey(conn); +		sshConnCache.put(serverName, conn); +		return conn; +	} + +	private void authenticateWithPublicKey(Connection conn) { +		try { +			if (!supportsPublicKeyAuthentication(conn)) { +				throw new GlusterRuntimeException("Public key authentication not supported on [" + conn.getHostname() +						+ "]"); +			} + +			// TODO: Introduce password for the PEM file (third argument) so that it is more secure +			if (!conn.authenticateWithPublicKey(USER_NAME, PEM_FILE, null)) { +				throw new GlusterRuntimeException("SSH Authentication (public key) failed for server [" +						+ conn.getHostname() + "]"); +			} +		} catch (IOException e) { +			e.printStackTrace(); +			throw new GlusterRuntimeException("Exception during SSH authentication (public key) for server [" +					+ conn.getHostname() + "]", e); +		} +	} + +	private void authenticateWithPassword(Connection conn) { +		try { +			if (!supportsPasswordAuthentication(conn)) { +				throw new GlusterRuntimeException("Password authentication not supported on [" + conn.getHostname() +						+ "]"); +			} + +			// TODO: Introduce password for the PEM file (third argument) so that it is more secure +			if (!conn.authenticateWithPassword(USER_NAME, DEFAULT_PASSWORD)) { +				throw new GlusterRuntimeException("SSH Authentication (password) failed for server [" +						+ conn.getHostname() + "]"); +			} +		} catch (IOException e) { +			e.printStackTrace(); +			throw new GlusterRuntimeException("Exception during SSH authentication (password) for server [" +					+ conn.getHostname() + "]", e); +		} +	} + +	private boolean supportsPasswordAuthentication(Connection conn) throws IOException { +		return Arrays.asList(conn.getRemainingAuthMethods(USER_NAME)).contains("password"); +	} + +	private boolean supportsPublicKeyAuthentication(Connection conn) throws IOException { +		return Arrays.asList(conn.getRemainingAuthMethods(USER_NAME)).contains("publickey"); +	} + +	private Connection createConnection(String serverName) { +		Connection conn; +		conn = new Connection(serverName); +		try { +			conn.connect(); +		} catch (IOException e) { +			e.printStackTrace(); +			throw new GlusterRuntimeException("Exception while creating SSH connection with server [" + serverName +					+ "]", e); +		} +		return conn; +	} + +	private boolean wasTerminated(int condition) { +		return ((condition | ChannelCondition.EXIT_SIGNAL) == condition); +	} + +	private boolean hasErrors(int condition, Session session) { +		return (hasErrorStream(condition) || (exitedGracefully(condition) && exitedWithError(session))); +	} + +	private boolean exitedWithError(Session session) { +		return session.getExitStatus() != ProcessResult.SUCCESS; +	} + +	private boolean exitedGracefully(int condition) { +		return (condition | ChannelCondition.EXIT_STATUS) == condition; +	} + +	private boolean hasErrorStream(int condition) { +		return (condition | ChannelCondition.STDERR_DATA) == condition; +	} + +	private ProcessResult executeCommand(Connection sshConnection, String command) { +		try { +			Session session = sshConnection.openSession(); +			BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(new StreamGobbler( +					session.getStdout()))); +			BufferedReader stderrReader = new BufferedReader(new InputStreamReader(new StreamGobbler( +					session.getStderr()))); +			session.execCommand(command); +			ProcessResult result = getResultOfExecution(session, stdoutReader, stderrReader); +			session.close(); +			return result; +		} catch (IOException e) { +			// TODO Auto-generated catch block +			e.printStackTrace(); +		} +		return null; +	} + +	private ProcessResult getResultOfExecution(Session session, BufferedReader stdoutReader, BufferedReader stderrReader) { +		// Wait for program to come out either +		// a) gracefully with an exit status, OR +		// b) because of a termination signal +		int condition = session.waitForCondition(ChannelCondition.EXIT_SIGNAL | ChannelCondition.EXIT_STATUS, 5000); +		StringBuilder output = new StringBuilder(); + +		try { +			readFromStream(stdoutReader, output); +			if (hasErrors(condition, session)) { +				readFromStream(stderrReader, output); +			} + +			return prepareProcessResult(session, condition, output); +		} catch (IOException e) { +			// TODO Auto-generated catch block +			e.printStackTrace(); +			return null; +		} +	} + +	private ProcessResult prepareProcessResult(Session session, int condition, StringBuilder output) { +		ProcessResult result = null; +		if (wasTerminated(condition)) { +			result = new ProcessResult(ProcessResult.FAILURE, output.toString()); +		} else { +			if (hasErrors(condition, session)) { +				Integer exitStatus = session.getExitStatus(); +				int statusCode = (exitStatus == null ? ProcessResult.FAILURE : exitStatus); +				result = new ProcessResult(statusCode, output.toString()); +			} else { +				result = new ProcessResult(ProcessResult.SUCCESS, output.toString()); +			} +		} +		return result; +	} + +	private void readFromStream(BufferedReader streamReader, StringBuilder output) throws IOException, +			UnsupportedEncodingException { +		while (true) { +			String line = streamReader.readLine(); +			if (line == null) { +				break; +			} +			output.append(line + CoreConstants.NEWLINE); +		} +	} + +	/** +	 * Executes given command on remote machine using password authentication +	 *  +	 * @param serverName +	 * @param command +	 * @return Result of remote execution +	 */ +	public ProcessResult executeRemoteWithPassword(String serverName, String command) { +		return executeCommand(getConnectionWithPassword(serverName), command); +	} + +	/** +	 * Executes given command on remote machine using public key authentication +	 *  +	 * @param serverName +	 * @param command +	 * @return Result of remote execution +	 */ +	public ProcessResult executeRemote(String serverName, String command) { +		return executeCommand(getConnection(serverName), command); +	} + +	/** +	 * Checks if public key of management gateway is configured on given server +	 *  +	 * @param serverName +	 * @return true if public key is configured, else false +	 */ +	public boolean isPublicKeySetup(String serverName) { +		try { +			getConnection(serverName); +			return true; +		} catch (Exception e) { +			return false; +		} +	} + +	public void cleanup() { +		for (Connection conn : sshConnCache.values()) { +			conn.close(); +		} +	} + +	public static void main(String[] args) { +		SshUtil sshUtil = new SshUtil(); +		System.out.println(new Date()); +		ProcessResult result = sshUtil.executeRemote("dev.gluster.com", "/bin/pwd"); +		System.out.println(result.getOutput()); +		result = sshUtil.executeRemote("dev.gluster.com", "/bin/pwd1"); +		System.out.println(new Date() + " - " + result.getExitValue() + " - " + result.getOutput()); +		result = sshUtil.executeRemote("dev.gluster.com", "/bin/ls -lrt"); +		System.out.println(new Date() + " - " + result.getExitValue() + " - " + result.getOutput()); + +		sshUtil.cleanup(); +	} +}  | 
