com.sun.enterprise.admin.cli.cluster.SSHCommandsBase Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2011 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.enterprise.admin.cli.cluster;
import java.io.*;
import java.net.URL;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import org.glassfish.internal.api.Globals;
import org.glassfish.internal.api.RelativePathResolver;
import org.glassfish.api.Param;
import org.glassfish.api.admin.*;
import com.sun.enterprise.admin.cli.CLICommand;
import org.glassfish.cluster.ssh.util.SSHUtil;
import org.glassfish.cluster.ssh.launcher.SSHLauncher;
import org.glassfish.cluster.ssh.sftp.SFTPClient;
import com.sun.enterprise.config.serverbeans.Domain;
import com.sun.enterprise.config.serverbeans.Nodes;
import com.sun.enterprise.config.serverbeans.Node;
import com.sun.enterprise.universal.glassfish.TokenResolver;
import com.sun.enterprise.util.io.DomainDirs;
import com.sun.enterprise.util.SystemPropertyConstants;
import com.sun.enterprise.util.StringUtils;
import com.sun.enterprise.util.net.NetUtils;
import com.trilead.ssh2.SFTPv3DirectoryEntry;
import org.jvnet.hk2.config.ConfigParser;
import org.jvnet.hk2.config.Dom;
import org.jvnet.hk2.config.DomDocument;
import org.jvnet.hk2.component.Habitat;
import org.glassfish.security.common.MasterPassword;
import com.sun.enterprise.security.store.PasswordAdapter;
/**
* Base class for SSH provisioning commands.
*
*/
public abstract class SSHCommandsBase extends CLICommand {
@Param(optional = true, defaultValue="${user.name}")
protected String sshuser;
@Param(optional=true, defaultValue="22")
protected int sshport;
@Param(optional = true)
protected String sshkeyfile;
@Param(optional = false, primary = true, multiple = true)
protected String[] hosts;
protected String sshpassword;
protected String sshkeypassphrase=null;
protected boolean promptPass=false;
protected TokenResolver resolver = null;
public SSHCommandsBase() {
// Create a resolver that can replace system properties in strings
Map systemPropsMap =
new HashMap((Map)(System.getProperties()));
resolver = new TokenResolver(systemPropsMap);
}
/**
* Get SSH password from password file or user.
*/
protected String getSSHPassword(String node) throws CommandException {
String password = getFromPasswordFile("AS_ADMIN_SSHPASSWORD");
if (password !=null ) {
String alias = RelativePathResolver.getAlias(password);
if (alias != null)
password = expandPasswordAlias(node, alias, true);
}
//get password from user if not found in password file
if (password == null) {
if (programOpts.isInteractive()) {
password=readPassword(Strings.get("SSHPasswordPrompt", sshuser, node));
} else {
throw new CommandException(Strings.get("SSHPasswordNotFound"));
}
}
return password;
}
/**
* Get SSH key passphrase from password file or user.
*/
protected String getSSHPassphrase(boolean verifyConn) throws CommandException {
String passphrase = getFromPasswordFile("AS_ADMIN_SSHKEYPASSPHRASE");
if (passphrase != null) {
String alias = RelativePathResolver.getAlias(passphrase);
if (alias != null)
passphrase = expandPasswordAlias(null, alias, verifyConn);
}
//get password from user if not found in password file
if (passphrase == null) {
if (programOpts.isInteractive()) {
//i18n
passphrase=readPassword(Strings.get("SSHPassphrasePrompt", sshkeyfile));
} else {
passphrase=""; //empty passphrase
}
}
return passphrase;
}
/**
* Get domain master password from password file or user.
*/
String getMasterPassword(String domain) throws CommandException {
String masterPass = getFromPasswordFile("AS_ADMIN_MASTERPASSWORD");
//get password from user if not found in password file
if (masterPass == null) {
if (programOpts.isInteractive()) {
//i18n
masterPass=readPassword(Strings.get("DomainMasterPasswordPrompt", domain));
} else {
masterPass="changeit"; //default
}
}
return masterPass;
}
private String getFromPasswordFile(String name) {
return passwords.get(name);
}
protected boolean isValidAnswer(String val) {
return val.equalsIgnoreCase("yes") || val.equalsIgnoreCase("no")
|| val.equalsIgnoreCase("y") || val.equalsIgnoreCase("n") ;
}
protected boolean isEncryptedKey() throws CommandException {
boolean res = false;
try {
res = SSHUtil.isEncryptedKey(sshkeyfile);
} catch (IOException ioe) {
throw new CommandException(Strings.get("ErrorParsingKey", sshkeyfile, ioe.getMessage()));
}
return res;
}
/**
* Method to delete files and directories on remote host
* 'nodes' directory is not considered for deletion since it would contain
* configuration information.
* @param sftpClient sftp client instance
* @param dasFiles file layout on DAS
* @param dir directory to be removed
* @param force true means delete all files, false means leave non-GlassFish files
* untouched
* @throws IOException in case of error
*/
protected void deleteRemoteFiles(SFTPClient sftpClient, List dasFiles, String dir, boolean force)
throws IOException {
for (SFTPv3DirectoryEntry directoryEntry: (List)sftpClient.ls(dir)) {
if (directoryEntry.filename.equals(".") || directoryEntry.filename.equals("..")
|| directoryEntry.filename.equals("nodes")) {
continue;
} else if (directoryEntry.attributes.isDirectory()) {
String f1 = dir+"/"+directoryEntry.filename;
deleteRemoteFiles(sftpClient, dasFiles, f1, force);
//only if file is present in DAS, it is targeted for removal on remote host
//using force deletes all files on remote host
if(force) {
logger.fine("Force removing directory " + f1);
sftpClient.rmdir(f1);
} else {
if (dasFiles.contains(f1))
sftpClient.rmdir(f1);
}
} else {
String f2 = dir+"/"+directoryEntry.filename;
if(force) {
logger.fine("Force removing file " + f2);
sftpClient.rm(f2);
} else {
if (dasFiles.contains(f2))
sftpClient.rm(f2);
}
}
}
}
/**
* Parses static domain.xml of all domains to determine if a node is configured
* for use.
* @param host remote host
* @return true|false
*/
protected boolean checkIfNodeExistsForHost(String host, String iDir) {
boolean result = false;
try {
File domainsDirFile = DomainDirs.getDefaultDomainsDir();
File[] files = domainsDirFile.listFiles(new FileFilter() {
public boolean accept(File f) {
return f.isDirectory();
}
});
for (File file: files) {
DomainDirs dir = new DomainDirs(file);
File domainXMLFile = dir.getServerDirs().getDomainXml();
logger.finer("Domain XML file = " + domainXMLFile);
try {
Habitat habitat = Globals.getStaticHabitat();
ConfigParser parser = new ConfigParser(habitat);
URL domainURL = domainXMLFile.toURI().toURL();
DomDocument doc = parser.parse(domainURL);
Dom domDomain = doc.getRoot();
Domain domain = domDomain.createProxy(Domain.class);
Nodes nodes = domain.getNodes();
for (Node node: nodes.getNode()) {
//make it Unix style and remove trailing slash
iDir = removeTrailingSlash(iDir.replaceAll("\\\\","/"));
String d = removeTrailingSlash(node.getInstallDirUnixStyle());
//check both hostname and install location
if ((NetUtils.isEqual(node.getNodeHost(), host) ||
NetUtils.isThisHostLocal(host)) && d.equals(iDir)) {
result = true;
}
}
} catch (Exception e) {
if(logger.isLoggable(Level.FINE)) {
e.printStackTrace();
}
}
}
} catch (IOException ioe) {
if(logger.isLoggable(Level.FINE)) {
ioe.printStackTrace();
}
}
return result;
}
/**
* Remove trailing slash from a path string
* @param s
* @return
*/
String removeTrailingSlash(String s) {
if (s.endsWith("/")) {
s = s.substring(0, s.length() - 1);
}
return s;
}
/**
* Obtains the real password from the domain specific keystore given an alias
* @param host host that we are connecting to
* @param alias password alias of form ${ALIAS=xxx}
* @return real password of ssh user, null if not found
*/
protected String expandPasswordAlias(String host, String alias, boolean verifyConn) {
String expandedPassword = null;
boolean connStatus = false;
try {
File domainsDirFile = DomainDirs.getDefaultDomainsDir();
//get the list of domains
File[] files = domainsDirFile.listFiles(new FileFilter() {
public boolean accept(File f) {
return f.isDirectory();
}
});
for (File f:files) {
//the following property is required for initializing the password helper
System.setProperty(SystemPropertyConstants.INSTANCE_ROOT_PROPERTY, f.getAbsolutePath());
try {
final MasterPassword masterPasswordHelper = Globals.getDefaultHabitat()
.getComponent(MasterPassword.class, "Security SSL Password Provider Service");
final PasswordAdapter pa = masterPasswordHelper.getMasterPasswordAdapter();
final boolean exists = pa.aliasExists(alias);
if (exists) {
String mPass = getMasterPassword(f.getName());
masterPasswordHelper.setMasterPassword(mPass.toCharArray());
expandedPassword = masterPasswordHelper.getMasterPasswordAdapter().getPasswordForAlias(alias);
}
} catch (Exception e) {
if(logger.isLoggable(Level.FINER)) {
logger.finer(StringUtils.cat(": ", alias, e.getMessage()));
}
logger.warning(Strings.get("GetPasswordFailure", f.getName()));
continue;
}
if(expandedPassword != null) {
SSHLauncher sshL = new SSHLauncher();
if (host != null) {
sshpassword = expandedPassword;
sshL.init(sshuser, host, sshport, sshpassword, null, null, logger);
connStatus = sshL.checkPasswordAuth();
if (!connStatus) {
logger.warning(Strings.get("PasswordAuthFailure", f.getName()));
}
} else {
sshkeypassphrase = expandedPassword;
if (verifyConn) {
sshL.init(sshuser, hosts[0], sshport, sshpassword, sshkeyfile, sshkeypassphrase, logger);
connStatus = sshL.checkConnection();
if (!connStatus) {
logger.warning(Strings.get("PasswordAuthFailure", f.getName()));
}
}
}
if (connStatus) {
break;
}
}
}
} catch (IOException ioe) {
if(logger.isLoggable(Level.FINER)) {
logger.finer(ioe.getMessage());
}
}
return expandedPassword;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy