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

com.sun.enterprise.admin.cli.cluster.ChangeNodeMasterPasswordCommand Maven / Gradle / Ivy

There is a newer version: 8.0.0-JDK17-M9
Show newest version
/*
 * Copyright (c) 2022 Contributors to the Eclipse Foundation
 * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package com.sun.enterprise.admin.cli.cluster;

import com.sun.enterprise.admin.servermgmt.NodeKeystoreManager;
import com.sun.enterprise.admin.servermgmt.RepositoryConfig;
import com.sun.enterprise.admin.util.CommandModelData.ParamModelData;
import com.sun.enterprise.security.store.PasswordAdapter;
import com.sun.enterprise.universal.i18n.LocalStringsImpl;
import com.sun.enterprise.universal.process.ProcessUtils;
import com.sun.enterprise.universal.xml.MiniXmlParser;
import com.sun.enterprise.universal.xml.MiniXmlParserException;
import com.sun.enterprise.util.HostAndPort;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.glassfish.api.Param;
import org.glassfish.api.admin.CommandException;
import org.glassfish.hk2.api.PerLookup;
import org.jvnet.hk2.annotations.Service;

/**
 * The change-master-password command for a node.
 * It takes in a nodeDir and node name
 *
 * @author Bhakti Mehta
 */
@Service(name = "_change-master-password-node")
@PerLookup
public  class ChangeNodeMasterPasswordCommand extends LocalInstanceCommand {

    @Param(name = "nodedir", optional = true)
    protected String nodeDir0;           // nodeDirRoot

    @Param(name = "node", primary = true)
    protected String node0;

    @Param(name = "savemasterpassword", optional = true, defaultValue = "false")
    protected boolean savemp;

    private static final String MASTER_PASSWORD_ALIAS="master-password";

    private static final LocalStringsImpl strings =
            new LocalStringsImpl(ChangeNodeMasterPasswordCommand.class);

    private String newPassword;

    private String oldPassword;


    @Override
    protected int executeCommand() throws CommandException {

        try {
            nodeDir = nodeDir0;
            node = node0;
            File serverDir = new File(nodeDir,node);

            if (!serverDir.isDirectory()) {
                throw new CommandException(strings.get("bad.node.dir",serverDir));
            }

            ArrayList serverNames = getInstanceDirs(serverDir);
            for (String serverName: serverNames) {
                if (isRunning(serverDir, serverName)) {
                    throw new CommandException(strings.get("instance.is.running",
                            serverName));
                }
            }

            oldPassword = passwords.get("AS_ADMIN_MASTERPASSWORD");
            if (oldPassword == null) {
                char[] opArr = super.readPassword(strings.get("old.mp"));
                oldPassword = opArr != null ? new String(opArr) : null;
            }
            if (oldPassword == null) {
                throw new CommandException(strings.get("no.console"));
            }

            // for each instance iterate through the instances first,
            // read each keystore with the old password,
            // only then should it save the new master password.
            boolean valid = true;
            for(String instanceDir0: getInstanceDirs(nodeDirChild)) {
               valid &= verifyInstancePassword(new File(nodeDirChild,instanceDir0));
           }
           if (!valid) {
               throw new CommandException(strings.get("incorrect.old.mp"));
           }
            ParamModelData nmpo = new ParamModelData("AS_ADMIN_NEWMASTERPASSWORD",
                    String.class, false, null);
            nmpo.prompt = strings.get("new.mp");
            nmpo.promptAgain = strings.get("new.mp.again");
            nmpo.param._password = true;
            char[] npArr = super.getPassword(nmpo, null, true);
            newPassword = npArr != null ? new String(npArr) : null;

            // for each instance encrypt the keystore
            for(String instanceDir2: getInstanceDirs(nodeDirChild)) {
               encryptKeystore(instanceDir2);
           }
            if (savemp) {
                createMasterPasswordFile();
            }
            return 0;
        } catch(Exception e) {
            throw new CommandException(e.getMessage(),e);
        }
    }

    /**
     * This will load and verify the keystore for each of the instances
     * in a node
     * @param instanceDir0 The instance directory
     * @return  if the password is valid for the instance keystore
     */
    private boolean verifyInstancePassword(File instanceDir) {

        File mp = new File(new File(instanceDir, "config"), "cacerts.jks");
        return loadAndVerifyKeystore(mp,oldPassword);
    }



    @Override
    public int execute(String... argv) throws CommandException {
        // We iterate through all the instances and so it should relax this requirement
        // that there is only 1 instance in a node .
        checkOneAndOnly = false;
        return super.execute(argv);
    }

    /**
     * Create the master password keystore. This routine can also modify the master password
     * if the keystore already exists
     *
     * @throws CommandException
     */
    protected void createMasterPasswordFile() throws CommandException {
        final File pwdFile = new File(this.getServerDirs().getAgentDir(), MASTER_PASSWORD_ALIAS);
        try {
            PasswordAdapter p = new PasswordAdapter(pwdFile.getAbsolutePath(),
                MASTER_PASSWORD_ALIAS.toCharArray());
            p.setPasswordForAlias(MASTER_PASSWORD_ALIAS, newPassword.getBytes());
            pwdFile.setReadable(true);
            pwdFile.setWritable(true);
        } catch (Exception ex) {
            throw new CommandException(strings.get("masterPasswordFileNotCreated", pwdFile), ex);
        }
    }


    /**
     * This will encrypt the keystore
     */
    public void encryptKeystore(String f) throws CommandException {

        RepositoryConfig nodeConfig = new RepositoryConfig(f,
                new File(nodeDir, node).toString(), f);
        NodeKeystoreManager km = new NodeKeystoreManager();
        try {
            km.encryptKeystore(nodeConfig,oldPassword,newPassword);

        } catch (Exception e) {
             throw new CommandException(strings.get("Keystore.not.encrypted"),
                e);
        }

    }

    /**
     * This will get all the instances for a given node
     * @param parent  node
     * @return   The list of instances for a node
     * @throws CommandException
     */
    private ArrayList getInstanceDirs(File parent) throws CommandException {

        ArrayList instancesList = new ArrayList<>();
        File[] files = parent.listFiles(File::isDirectory);
        if (files == null || files.length == 0) {
            throw new CommandException(strings.get("Instance.noInstanceDirs", parent));
        }

        for (File f : files) {
            if (!f.getName().equals("agent")) {
                instancesList.add(f.getName());
            }
        }
        return instancesList;

    }


    private boolean isRunning(File nodeDirChild, String serverName) throws CommandException {
        try {
            File serverDir = new File(nodeDirChild, serverName);
            File configDir = new File(serverDir, "config");
            File domainXml = new File(configDir, "domain.xml");
            if (!domainXml.exists()) {
                return false;
            }
            MiniXmlParser parser = new MiniXmlParser(domainXml, serverName);
            List addrSet = parser.getAdminAddresses();
            if (addrSet.isEmpty()) {
                throw new CommandException(strings.get("NoAdminPort"));
            }
            HostAndPort addr = addrSet.get(0);
            return ProcessUtils.isListening(addr);
        } catch (MiniXmlParserException ex) {
            throw new CommandException(strings.get("NoAdminPortEx", ex), ex);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy