All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.enterprise.admin.cli.LocalServerCommand Maven / Gradle / Ivy

There is a newer version: 10.0-b28
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2010 Sun Microsystems, Inc. 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.html
 * or glassfish/bootstrap/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 glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [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;

import com.sun.enterprise.admin.cli.remote.RemoteCommand;
import com.sun.enterprise.security.store.PasswordAdapter;
import com.sun.enterprise.universal.i18n.LocalStringsImpl;
import com.sun.enterprise.universal.io.SmartFile;
import com.sun.enterprise.universal.xml.MiniXmlParser;
import com.sun.enterprise.universal.xml.MiniXmlParserException;
import java.io.*;
import java.io.File;
import com.sun.enterprise.util.io.ServerDirs;
import java.net.*;
import java.security.KeyStore;
import java.util.*;
import java.util.Set;
import org.glassfish.api.admin.CommandException;

/**
 * A class that's supposed to capture all the behavior common to operation
 * on a "local" server.
 * It's getting fairly complicated thus the "section headers" comments.
 * This class plays two roles, 
  • a place for putting common code - which * are final methods. A parent class that is communicating with its own unknown * sub-classes. These are non-final methods * * @author Byron Nevins */ public abstract class LocalServerCommand extends CLICommand { //////////////////////////////////////////////////////////////// /// Section: protected methods that are OK to override //////////////////////////////////////////////////////////////// /** * Override this method and return false to turn-off the file validation. * E.g. it demands that config/domain.xml be present. In special cases like * Synchronization -- this is how you turn off the testing. * @return true - do the checks, false - don't do the checks */ protected boolean checkForSpecialFiles() { return true; } //////////////////////////////////////////////////////////////// /// Section: protected methods that are notOK to override. //////////////////////////////////////////////////////////////// /** * Returns the admin port of the local domain. Note that this method should * be called only when you own the domain that is available on accessible * file system. * * @return an integer that represents admin port * @throws CommandException in case of parsing errors */ protected final int getAdminPort() throws CommandException { // default: DAS which always has the name "server" return getAdminPort("server"); } /** * Returns the admin port of a particular server. Note that this method should * be called only when you own the server that is available on accessible * file system. * * @return an integer that represents admin port * @throws CommandException in case of parsing errors */ protected final int getAdminPort(String serverName) throws CommandException { try { MiniXmlParser parser = new MiniXmlParser(getDomainXml(), serverName); Set portsSet = parser.getAdminPorts(); if(portsSet.size() > 0) return portsSet.iterator().next(); else throw new CommandException("admin port not found"); } catch (MiniXmlParserException ex) { throw new CommandException("admin port not found", ex); } } protected final void setServerDirs(ServerDirs sd) { serverDirs = sd; } protected final void resetServerDirs() throws IOException { serverDirs = serverDirs.refresh(); } protected final ServerDirs getServerDirs() { return serverDirs; } protected final File getDomainXml() { return serverDirs.getDomainXml(); } /** * Checks if the create-domain was created using --savemasterpassword flag * which obtains security by obfuscation! Returns null in case of failure * of any kind. * @return String representing the password from the JCEKS store named * master-password in domain folder */ protected final String readFromMasterPasswordFile() { File mpf = getMasterPasswordFile(); if(mpf == null) return null; // no master password saved try { PasswordAdapter pw = new PasswordAdapter(mpf.getAbsolutePath(), "master-password".toCharArray()); // fixed key return pw.getPasswordForAlias("master-password"); } catch (Exception e) { logger.printDebugMessage("master password file reading error: " + e.getMessage()); return null; } } protected final boolean verifyMasterPassword(String mpv) { // only tries to open the keystore FileInputStream fis = null; try { fis = new FileInputStream(getJKS()); KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(fis, mpv.toCharArray()); return true; } catch (Exception e) { logger.printDebugMessage(e.getMessage()); return false; } finally { try { if(fis != null) fis.close(); } catch (IOException ioe) { // ignore, I know ... } } } /** * Get the master password, either from a password file or * by asking the user. */ protected final String getMasterPassword() throws CommandException { // Sets the password into the launcher info. // Yes, returning master password as a string is not right ... final int RETRIES = 3; long t0 = System.currentTimeMillis(); String mpv = passwords.get(CLIConstants.MASTER_PASSWORD); if(mpv == null) { //not specified in the password file mpv = "changeit"; //optimization for the default case -- see 9592 if(!verifyMasterPassword(mpv)) { mpv = readFromMasterPasswordFile(); if(!verifyMasterPassword(mpv)) { mpv = retry(RETRIES); } } } else { // the passwordfile contains AS_ADMIN_MASTERPASSWORD, use it if(!verifyMasterPassword(mpv)) mpv = retry(RETRIES); } long t1 = System.currentTimeMillis(); logger.printDebugMessage("Time spent in master password extraction: " + (t1 - t0) + " msec"); //TODO return mpv; } /** * See if the server is alive and is the one at the specified directory. * * @return true if it's the DAS at this domain directory */ protected final boolean isThisServer(File ourDir, String directoryKey) { if(!ok(directoryKey)) throw new NullPointerException(); ourDir = getUniquePath(ourDir); logger.printDebugMessage("Check if server is at location " + ourDir); try { RemoteCommand cmd = new RemoteCommand("__locations", programOpts, env); Map attrs = cmd.executeAndReturnAttributes(new String[]{"__locations"}); String theirDirPath = attrs.get(directoryKey); logger.printDebugMessage("Remote server has root directory " + theirDirPath); if(ok(theirDirPath)) { File theirDir = getUniquePath(new File(theirDirPath)); return theirDir.equals(ourDir); } return false; } catch (Exception ex) { return false; } } /** * There is sometimes a need for subclasses to know if a * local domain is running. An example of such a command is * change-master-password command. The stop-domain command also needs to * know if a domain is running without having to provide user * name and password on command line (this is the case when I own a domain * that has non-default admin user and password) and want to stop it * without providing it. *

    * In such cases, we need to know if the domain is running and this method * provides a way to do that. * * @return boolean indicating whether the server is running */ protected final boolean isRunning(String host, int port) { Socket server = null; try { server = new Socket(host, port); return true; } catch (Exception ex) { logger.printDebugMessage("\nisRunning got exception: " + ex); return false; } finally { if(server != null) { try { server.close(); } catch (IOException ex) { } } } } /** * convenience method for the local machine */ protected final boolean isRunning(int port) { return isRunning(null, port); } /** * Is the server still running? * This is only called when we're hanging around waiting for the server to die. */ protected final boolean isRunning() { File pf = getServerDirs().getPidFile(); if(pf != null) { return pf.exists(); } else return isRunning(programOpts.getHost(), // remote case programOpts.getPort()); } //////////////////////////////////////////////////////////////// /// Section: private methods //////////////////////////////////////////////////////////////// private final File getJKS() { if(serverDirs == null) return null; File mp = new File(new File(serverDirs.getServerDir(), "config"), "keystore.jks"); if(!mp.canRead()) return null; return mp; } private File getMasterPasswordFile() { if(serverDirs == null) return null; File mp = new File(serverDirs.getServerDir(), "master-password"); if(!mp.canRead()) return null; return mp; } private String retry(int times) throws CommandException { String mpv; // prompt times times for(int i = 0; i < times; i++) { // XXX - I18N String prompt = strings.get("mp.prompt", (times - i)); mpv = super.readPassword(prompt); if(mpv == null) throw new CommandException(strings.get("no.console")); // ignore retries :) if(verifyMasterPassword(mpv)) return mpv; if(i < (times - 1)) logger.printMessage(strings.get("retry.mp")); // make them pay for typos? //Thread.currentThread().sleep((i+1)*10000); } throw new CommandException(strings.get("mp.giveup", times)); } private File getUniquePath(File f) { try { f = f.getCanonicalFile(); } catch (IOException ioex) { f = SmartFile.sanitize(f); } return f; } //////////////////////////////////////////////////////////////// /// Section: private variables //////////////////////////////////////////////////////////////// private ServerDirs serverDirs; private static final LocalStringsImpl strings = new LocalStringsImpl(LocalDomainCommand.class); }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy