/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2022 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jboss.installer.postinstall.task;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.PathAddress;
import org.jboss.dmr.ModelNode;
import org.jboss.installer.auto.InstallationDataSerializer;
import org.jboss.installer.core.InstallationData;
import org.jboss.installer.postinstall.TaskPrinter;
import org.jboss.installer.postinstall.server.DomainServer;
import org.jboss.installer.postinstall.server.ServerOperationException;
import org.jboss.installer.postinstall.server.StandaloneServer;
import org.jboss.installer.test.utils.MockLanguageUtils;
import org.jboss.installer.test.utils.TestServer;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import static org.jboss.as.controller.operations.common.Util.createEmptyOperation;
import static org.jboss.installer.postinstall.task.AbstractHttpsEnableTask.CLIENT_KEY_ALIAS;
import static org.jboss.installer.postinstall.task.AbstractHttpsEnableTask.SERVER_KEY_ALIAS;
import static org.jboss.installer.postinstall.task.HttpsEnableTask.CREDENTIAL_ALIAS_KEYSTORE_PASSWORD;
import static org.jboss.installer.postinstall.task.HttpsEnableTask.CREDENTIAL_ALIAS_TRUSTSTORE_PASSWORD;
import static org.jboss.installer.postinstall.task.HttpsEnableTask.Config.KEYSTORE_PASSWORD_VARIABLE_KEY;
import static org.jboss.installer.postinstall.task.HttpsEnableTask.Config.TRUSTSTORE_PASSWORD_VARIABLE_KEY;
import static org.jboss.installer.postinstall.task.HttpsEnableTask.DEFAULT_CIPHER_SUITES_TLS12;
import static org.jboss.installer.postinstall.task.HttpsEnableTask.DEFAULT_CIPHER_NAMES_TLS13;
import static org.jboss.installer.postinstall.task.HttpsEnableTask.MANAGEMENT_KEYMANAGER_NAME;
import static org.jboss.installer.postinstall.task.HttpsEnableTask.MANAGEMENT_KEYSTORE_NAME;
import static org.jboss.installer.postinstall.task.HttpsEnableTask.MANAGEMENT_SSL_CONTEXT_NAME;
import static org.jboss.installer.postinstall.task.HttpsEnableTask.MANAGEMENT_TRUSTMANAGER_NAME;
import static org.jboss.installer.postinstall.task.HttpsEnableTask.MANAGEMENT_TRUSTSTORE_NAME;
import static org.jboss.installer.postinstall.task.HttpsEnableTask.PROTOCOL_TLSv12;
import static org.jboss.installer.postinstall.task.HttpsEnableTask.PROTOCOL_TLSv13;
import static org.jboss.installer.postinstall.task.PortConfigurationTask.DOMAIN_MANAGEMENT_HTTPS_PORT_DEFAULT;
import static org.jboss.installer.postinstall.task.PortConfigurationTask.DOMAIN_MANAGEMENT_HTTPS_PORT_PROPERTY;
import static org.jboss.installer.test.utils.TestServer.TARGET_PATH;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

public class HttpsEnableTaskTest {
    private static final String KEYSTORE_PASSWORD = "keystore-secret";
    private static final String KEYSTORE_PATH = "test.keystore";
    private static final String TRUSTSTORE_PASSWORD = "truststore-secret";
    private static final String TRUSTSTORE_PATH = "test.truststore";
    private static final String TEST_DN = "CN=test";
    private static final String VALIDITY = "30";
    private static final String CLIENT_CERT_PATH = Paths.get("src", "test", "resources", "client.crt").toAbsolutePath().toString();
    private static final boolean WITH_CREDENTIAL_STORE = true;
    private static final boolean NO_CREDENTIAL_STORE = false;

    private static final HttpsEnableTask.Config KEYSTORE_CONFIG = new HttpsEnableTask.Config(
            Set.of(PROTOCOL_TLSv12), DEFAULT_CIPHER_SUITES_TLS12, DEFAULT_CIPHER_NAMES_TLS13, KEYSTORE_PATH, KEYSTORE_PASSWORD,
            false, null, null,
            false, null, null, null, false);
    private static final HttpsEnableTask.Config TRUSTSTORE_CONFIG = new HttpsEnableTask.Config(
            Set.of(PROTOCOL_TLSv12), DEFAULT_CIPHER_SUITES_TLS12, DEFAULT_CIPHER_NAMES_TLS13, KEYSTORE_PATH, KEYSTORE_PASSWORD,
            true, TRUSTSTORE_PATH, TRUSTSTORE_PASSWORD,
            false, null, null, null, false);
    private static final HttpsEnableTask.Config TLSv13_CONFIG = new HttpsEnableTask.Config(
            Set.of(PROTOCOL_TLSv13), DEFAULT_CIPHER_SUITES_TLS12, DEFAULT_CIPHER_NAMES_TLS13, KEYSTORE_PATH, KEYSTORE_PASSWORD,
            false, null, null,
            false, null, null, null, false);
    private static final HttpsEnableTask.Config GENERATE_KEYSTORE_CONFIG = new HttpsEnableTask.Config(
            Set.of(PROTOCOL_TLSv12), DEFAULT_CIPHER_SUITES_TLS12, DEFAULT_CIPHER_NAMES_TLS13, null, KEYSTORE_PASSWORD,
            false, null, null,
            true, TEST_DN, VALIDITY, null, false);
    private static final HttpsEnableTask.Config GENERATE_TRUSTSTORE_CONFIG = new HttpsEnableTask.Config(
            Set.of(PROTOCOL_TLSv12), DEFAULT_CIPHER_SUITES_TLS12, DEFAULT_CIPHER_NAMES_TLS13, null, KEYSTORE_PASSWORD,
            true, null, TRUSTSTORE_PASSWORD,
            true, TEST_DN, VALIDITY, CLIENT_CERT_PATH, false);
    private static final HttpsEnableTask.Config FULL_CONFIG = new HttpsEnableTask.Config(
            Set.of(PROTOCOL_TLSv13), DEFAULT_CIPHER_SUITES_TLS12, DEFAULT_CIPHER_NAMES_TLS13, KEYSTORE_PATH, KEYSTORE_PASSWORD,
            true, TRUSTSTORE_PATH, TRUSTSTORE_PASSWORD,
            true, TEST_DN, VALIDITY, CLIENT_CERT_PATH, true);

    @ClassRule
    public static TestServer testServer = new TestServer();

    @Rule
    public TemporaryFolder temp = new TemporaryFolder();

    private final CredentialStoreInstallTask.Config credStoreConfig = new CredentialStoreInstallTask.Config("test-store", null, TARGET_PATH.resolve("test.store").toString(), "abcd1234");

    private StandaloneServer standaloneServer;
    private DomainServer domainServer;
    private XPath xPath =  XPathFactory.newInstance().newXPath();
    private DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    private DocumentBuilder builder;
    private InstallationData iData = new InstallationData();
    private TaskPrinter printer = new NoopPrinter();

    @Before
    public void setUp() throws Exception {
        standaloneServer = new StandaloneServer(TARGET_PATH);
        domainServer = new DomainServer(TARGET_PATH);
        builder = factory.newDocumentBuilder();

        // copy the configuration file so that we can quickly restore it between tests
        FileUtils.copyDirectory(TARGET_PATH.resolve("domain").resolve("configuration").toFile(), TARGET_PATH.resolve("domain").resolve("backup").toFile());
        FileUtils.copyDirectory(TARGET_PATH.resolve("standalone").resolve("configuration").toFile(), TARGET_PATH.resolve("standalone").resolve("backup").toFile());
    }

    @After
    public void tearDown() throws Exception {
        FileUtils.deleteDirectory(TARGET_PATH.resolve("domain").resolve("configuration").toFile());
        FileUtils.deleteDirectory(TARGET_PATH.resolve("standalone").resolve("configuration").toFile());
        FileUtils.copyDirectory(TARGET_PATH.resolve("domain").resolve("backup").toFile(), TARGET_PATH.resolve("domain").resolve("configuration").toFile());
        FileUtils.copyDirectory(TARGET_PATH.resolve("standalone").resolve("backup").toFile(), TARGET_PATH.resolve("standalone").resolve("configuration").toFile());
        FileUtils.deleteDirectory(TARGET_PATH.resolve("domain").resolve("backup").toFile());
        FileUtils.deleteDirectory(TARGET_PATH.resolve("standalone").resolve("backup").toFile());
    }

    @Test
    public void addKeystoreToStandalone() throws Exception {
        final String config = "standalone.xml";
        testStandalone(config, KEYSTORE_CONFIG, NO_CREDENTIAL_STORE);
    }

    @Test
    public void addTrustStoreToStandalone() throws Exception {
        final String config = "standalone.xml";
        testStandalone(config, TRUSTSTORE_CONFIG, NO_CREDENTIAL_STORE);
    }

    @Test
    public void addKeystoreToStandaloneWithCredentialStore() throws Exception {
        final String config = "standalone.xml";
        testStandalone(config, KEYSTORE_CONFIG, WITH_CREDENTIAL_STORE);

        // keystore password needs to be added to store only once
        testStandalone("standalone-ha.xml", KEYSTORE_CONFIG, WITH_CREDENTIAL_STORE);
    }

    @Test
    public void addTrustStoreToStandaloneWithCredentialStore() throws Exception {
        final String config = "standalone.xml";
        testStandalone(config, TRUSTSTORE_CONFIG, WITH_CREDENTIAL_STORE);

        // keystore password needs to be added to store only once
        testStandalone("standalone-ha.xml", TRUSTSTORE_CONFIG, WITH_CREDENTIAL_STORE);
    }

    @Test
    public void addKeystoreToDomainWithCredentialStore() throws Exception {
        final String config = "host.xml";
        testDomain(config, KEYSTORE_CONFIG, WITH_CREDENTIAL_STORE);
    }

    @Test
    public void addTrustStoreToDomainWithCredentialStore() throws Exception {
        final String config = "host.xml";
        testDomain(config, TRUSTSTORE_CONFIG, WITH_CREDENTIAL_STORE);
    }

    @Test
    public void addKeystoreToStandaloneFullHa() throws Exception {
        final String config = "standalone-full-ha.xml";
        testStandalone(config, KEYSTORE_CONFIG, NO_CREDENTIAL_STORE);
    }

    @Test
    public void addTrustStoreToStandaloneFullHa() throws Exception {
        final String config = "standalone-full-ha.xml";
        testStandalone(config, TRUSTSTORE_CONFIG, NO_CREDENTIAL_STORE);
    }

    @Test
    public void addKeystoreToDomain() throws Exception {
        final String config = "host.xml";

        testDomain(config, KEYSTORE_CONFIG, NO_CREDENTIAL_STORE);
    }

    @Test
    public void addTruststoreToDomain() throws Exception {
        final String config = "host.xml";

        testDomain(config, TRUSTSTORE_CONFIG, NO_CREDENTIAL_STORE);
    }

    @Test
    public void addKeystoreToDomainSecondary() throws Exception {
        final String config = DomainServer.HOST_SECONDARY_XML;

        testDomain(config, KEYSTORE_CONFIG, NO_CREDENTIAL_STORE);
    }

    @Test
    public void addTrustStoreToDomainSecondary() throws Exception {
        final String config = DomainServer.HOST_SECONDARY_XML;

        testDomain(config, TRUSTSTORE_CONFIG, NO_CREDENTIAL_STORE);
    }

    @Test
    public void usePortOffsetInDomain() throws Exception {
        final String config = "host.xml";
        iData.putConfig(KEYSTORE_CONFIG);
        iData.putConfig(new PortConfigurationTask.Config(100));

        try {
            domainServer.start(config);

            new HttpsEnableTask().applyToDomain(iData, domainServer, printer);

            Document hostDoc = builder.parse(TARGET_PATH.resolve("domain").resolve("configuration").resolve(config).toFile());

            assertEquals("${" + DOMAIN_MANAGEMENT_HTTPS_PORT_PROPERTY + ":10093}", getAttribute(hostDoc, "//management-interfaces/http-interface/socket",
                    "secure-port"));
        } finally {
            domainServer.shutdown();
        }
    }

    @Test
    public void testSerializeDeserialize() throws Exception {
        iData.putConfig(FULL_CONFIG);
        final Path tempFile = temp.newFile("auto.xml").toPath();
        final InstallationDataSerializer serializer = new InstallationDataSerializer(new MockLanguageUtils());
        serializer.serialize(iData, tempFile);
        List<String> passwords = List.of(
                KEYSTORE_PASSWORD_VARIABLE_KEY + "=" + FULL_CONFIG.getKeyStorePassword(),
                TRUSTSTORE_PASSWORD_VARIABLE_KEY + "=" + FULL_CONFIG.getTrustStorePassword());
        FileUtils.writeLines(tempFile.getParent().resolve(tempFile.getFileName().toString() + ".variables").toFile(), "UTF-8", passwords);
        final InstallationData loadedData = serializer.deserialize(tempFile, Optional.empty());

        final HttpsEnableTask.Config config = loadedData.getConfig(HttpsEnableTask.Config.class);
        assertEquals(FULL_CONFIG, config);
    }

    @Test
    public void testTLSv13() throws Exception {
        final String config = "standalone.xml";
        testStandalone(config, TLSv13_CONFIG, NO_CREDENTIAL_STORE);
    }

    @Test
    public void generateKeystoreInStandalone() throws Exception {
        final String config = "standalone.xml";
        clearStateOf(GENERATE_KEYSTORE_CONFIG);
        testStandalone(config, GENERATE_KEYSTORE_CONFIG, NO_CREDENTIAL_STORE, MANAGEMENT_KEYSTORE_NAME);
    }

    @Test
    public void generateKeystoreInStandaloneWithCredentialStore() throws Exception {
        final String config = "standalone.xml";
        clearStateOf(GENERATE_KEYSTORE_CONFIG);
        testStandalone(config, GENERATE_KEYSTORE_CONFIG, WITH_CREDENTIAL_STORE, MANAGEMENT_KEYSTORE_NAME);
    }

    @Test
    public void generateKeystoreInDomain() throws Exception {
        final String config = "host.xml";
        clearStateOf(GENERATE_KEYSTORE_CONFIG);
        testDomain(config, GENERATE_KEYSTORE_CONFIG, NO_CREDENTIAL_STORE, MANAGEMENT_KEYSTORE_NAME);
    }

    @Test
    public void generateKeystoreInDomainWithCredentialStore() throws Exception {
        final String config = "host.xml";
        clearStateOf(GENERATE_KEYSTORE_CONFIG);
        testDomain(config, GENERATE_KEYSTORE_CONFIG, WITH_CREDENTIAL_STORE, MANAGEMENT_KEYSTORE_NAME);
    }

    @Test
    public void generateTrustStoreInStandalone() throws Exception {
        final String config = "standalone.xml";
        clearStateOf(GENERATE_TRUSTSTORE_CONFIG);
        testStandalone(config, GENERATE_TRUSTSTORE_CONFIG, NO_CREDENTIAL_STORE, MANAGEMENT_KEYSTORE_NAME, MANAGEMENT_TRUSTSTORE_NAME);
    }

    @Test
    public void generateTrustStoreInStandaloneWithCredentialStore() throws Exception {
        final String config = "standalone.xml";
        clearStateOf(GENERATE_TRUSTSTORE_CONFIG);
        testStandalone(config, GENERATE_TRUSTSTORE_CONFIG, WITH_CREDENTIAL_STORE, MANAGEMENT_KEYSTORE_NAME, MANAGEMENT_TRUSTSTORE_NAME);
    }

    @Test
    public void generateTrustStoreInDomain() throws Exception {
        final String config = "host.xml";
        clearStateOf(GENERATE_TRUSTSTORE_CONFIG);
        testDomain(config, GENERATE_TRUSTSTORE_CONFIG, NO_CREDENTIAL_STORE, MANAGEMENT_KEYSTORE_NAME, MANAGEMENT_TRUSTSTORE_NAME);
    }

    @Test
    public void generateTrustStoreInDomainWithCredentialStore() throws Exception {
        final String config = "host.xml";
        clearStateOf(GENERATE_TRUSTSTORE_CONFIG);
        testDomain(config, GENERATE_TRUSTSTORE_CONFIG, WITH_CREDENTIAL_STORE, MANAGEMENT_KEYSTORE_NAME, MANAGEMENT_TRUSTSTORE_NAME);
    }

    private void testStandalone(String config, HttpsEnableTask.Config httpsConfig, boolean credStore) throws ServerOperationException, SAXException, IOException, XPathExpressionException, OperationFailedException {
        testStandalone(config, httpsConfig, credStore, null, null);
    }

    private void testStandalone(String config, HttpsEnableTask.Config httpsConfig, boolean credStore, String keyStoreNameToTest) throws ServerOperationException, SAXException, IOException, XPathExpressionException, OperationFailedException {
        testStandalone(config, httpsConfig, credStore, keyStoreNameToTest, null);
    }

    private void testStandalone(String config, HttpsEnableTask.Config httpsConfig, boolean credStore, String keyStoreNameToTest, String trustStoreNameToTest) throws ServerOperationException, SAXException, IOException, XPathExpressionException, OperationFailedException {
        iData.setTargetFolder(TARGET_PATH);
        iData.putConfig(httpsConfig);
        if (credStore) {
            iData.putConfig(credStoreConfig);
        }
        try {
            standaloneServer.start(config);

            if (credStore) {
                assertTrue(new CredentialStoreInstallTask().applyToStandalone(iData, standaloneServer, printer));
            }
            assertTrue(new HttpsEnableTask().applyToStandalone(iData, standaloneServer, printer));

            verifyStandalone(config, httpsConfig, credStore);
            if (keyStoreNameToTest != null) {
                verifyAliasInKeyStore(standaloneServer, keyStoreNameToTest, SERVER_KEY_ALIAS);
            }
            if (trustStoreNameToTest != null) {
                verifyAliasInKeyStore(standaloneServer, trustStoreNameToTest, CLIENT_KEY_ALIAS);
            }
        } finally {
            standaloneServer.shutdown();
        }
    }

    private void testDomain(String config, HttpsEnableTask.Config httpsConfig, boolean credStore) throws ServerOperationException, SAXException, IOException, XPathExpressionException, OperationFailedException {
        testDomain(config, httpsConfig, credStore, null);
    }

    private void testDomain(String config, HttpsEnableTask.Config httpsConfig, boolean credStore, String keyStoreNameToTest) throws ServerOperationException, SAXException, IOException, XPathExpressionException, OperationFailedException {
        testDomain(config, httpsConfig, credStore, keyStoreNameToTest, null);
    }

    private void testDomain(String config, HttpsEnableTask.Config httpsConfig, boolean credStore, String keyStoreNameToTest, String trustStoreNameToTest) throws ServerOperationException, SAXException, IOException, XPathExpressionException, OperationFailedException {
        iData.setTargetFolder(TARGET_PATH);
        iData.putConfig(httpsConfig);
        if (credStore) {
            iData.putConfig(credStoreConfig);
        }
        try {
            domainServer.start(config);

            if (credStore) {
                assertTrue(new CredentialStoreInstallTask().applyToDomain(iData, domainServer, printer));
            }
            assertTrue(new HttpsEnableTask().applyToDomain(iData, domainServer, printer));

            verifyHostConfig(config, httpsConfig, credStore);
            if (keyStoreNameToTest != null) {
                verifyAliasInKeyStore(domainServer, keyStoreNameToTest, SERVER_KEY_ALIAS);
            }
            if (trustStoreNameToTest != null) {
                verifyAliasInKeyStore(domainServer, trustStoreNameToTest, CLIENT_KEY_ALIAS);
            }
        } finally {
            domainServer.shutdown();
        }
    }

    private void verifyStandalone(String config, HttpsEnableTask.Config httpsConfig, boolean credStore) throws SAXException, IOException, XPathExpressionException {
        Document doc = builder.parse(TARGET_PATH.resolve("standalone").resolve("configuration").resolve(config).toFile());
        verifyCommonElements(doc, httpsConfig, credStore);

        assertEquals("management-https", getAttribute(doc, "//management-interfaces/http-interface/socket-binding",
                "https"));
        assertNull("http socket binding has been removed", getAttribute(doc, "//management-interfaces/http-interface/socket-binding",
                "http"));
    }

    private void verifyHostConfig(String config, HttpsEnableTask.Config httpsConfig, boolean credStore) throws SAXException, IOException, XPathExpressionException {
        Document hostDoc = builder.parse(TARGET_PATH.resolve("domain").resolve("configuration").resolve(config).toFile());
        verifyCommonElements(hostDoc, httpsConfig, credStore);

        assertEquals(String.format("${%s:%s}",DOMAIN_MANAGEMENT_HTTPS_PORT_PROPERTY, DOMAIN_MANAGEMENT_HTTPS_PORT_DEFAULT),
                getAttribute(hostDoc, "//management-interfaces/http-interface/socket",
                        "secure-port"));
        assertNull(getAttribute(hostDoc, "//management-interfaces/http-interface/socket",
                "port"));
    }

    private void verifyCommonElements(Document doc, HttpsEnableTask.Config httpsConfig, boolean credStore) throws XPathExpressionException {
        // verify key store
        if (!httpsConfig.isDoGenerateStore()) {
            assertEquals(httpsConfig.getKeyStorePath(), getAttribute(doc, "//key-stores/key-store[@name=\"" + MANAGEMENT_KEYSTORE_NAME + "\"]/file", "path"));
        }
        // assert has alias and store
        if (credStore) {
            assertEquals("test-store",
                    getAttribute(doc, "//key-stores/key-store[@name=\"" + MANAGEMENT_KEYSTORE_NAME + "\"]/credential-reference",
                            "store"));
            assertEquals(CREDENTIAL_ALIAS_KEYSTORE_PASSWORD,
                    getAttribute(doc, "//key-stores/key-store[@name=\"" + MANAGEMENT_KEYSTORE_NAME + "\"]/credential-reference",
                            "alias"));
        } else {
            assertEquals(httpsConfig.getKeyStorePassword(),
                    getAttribute(doc, "//key-stores/key-store[@name=\"" + MANAGEMENT_KEYSTORE_NAME + "\"]/credential-reference",
                            "clear-text"));
        }
        // verify optional trust store
        if (httpsConfig.isMutual()) {
            if (!httpsConfig.isDoGenerateStore()) {
                assertEquals(httpsConfig.getTrustStorePath(), getAttribute(doc, "//key-stores/key-store[@name=\"" + MANAGEMENT_TRUSTSTORE_NAME + "\"]/file", "path"));
            }
            if (credStore) {
                assertEquals("test-store",
                        getAttribute(doc, "//key-stores/key-store[@name=\"" + MANAGEMENT_TRUSTSTORE_NAME + "\"]/credential-reference",
                                "store"));
                assertEquals(CREDENTIAL_ALIAS_TRUSTSTORE_PASSWORD,
                        getAttribute(doc, "//key-stores/key-store[@name=\"" + MANAGEMENT_TRUSTSTORE_NAME + "\"]/credential-reference",
                                "alias"));
            } else {
                assertEquals(httpsConfig.getTrustStorePassword(),
                        getAttribute(doc, "//key-stores/key-store[@name=\"" + MANAGEMENT_TRUSTSTORE_NAME + "\"]/credential-reference",
                                "clear-text"));
            }
            assertEquals(MANAGEMENT_TRUSTMANAGER_NAME,
                    getAttribute(doc, "//server-ssl-contexts/server-ssl-context[@name=\"" + MANAGEMENT_SSL_CONTEXT_NAME + "\"]",
                            "trust-manager"));
            assertEquals("true",
                    getAttribute(doc, "//server-ssl-contexts/server-ssl-context[@name=\"" + MANAGEMENT_SSL_CONTEXT_NAME + "\"]",
                            "need-client-auth"));
        }

        // verify key manager
        assertEquals(MANAGEMENT_KEYMANAGER_NAME,
                getAttribute(doc, "//server-ssl-contexts/server-ssl-context[@name=\"" + MANAGEMENT_SSL_CONTEXT_NAME + "\"]",
                        "key-manager"));

        // verify TLS protocol
        if (httpsConfig.getProtocols() != null && !httpsConfig.getProtocols().isEmpty()) {
            assertEquals(StringUtils.join(httpsConfig.getProtocols(), ", "),
                    getAttribute(doc, "//server-ssl-contexts/server-ssl-context[@name=\"" + MANAGEMENT_SSL_CONTEXT_NAME + "\"]",
                            "protocols"));
            if (httpsConfig.getCipherSuites() != null) {
                assertEquals(httpsConfig.getCipherSuites(),
                        getAttribute(doc, "//server-ssl-contexts/server-ssl-context[@name=\"" + MANAGEMENT_SSL_CONTEXT_NAME + "\"]",
                                "cipher-suite-filter"));
            }
            if (httpsConfig.getTls13cipherNames() != null) {
                assertEquals(httpsConfig.getTls13cipherNames(),
                        getAttribute(doc, "//server-ssl-contexts/server-ssl-context[@name=\"" + MANAGEMENT_SSL_CONTEXT_NAME + "\"]",
                                "cipher-suite-names"));
            }
        }

        // verify SSL Context
        assertEquals(MANAGEMENT_SSL_CONTEXT_NAME, getAttribute(doc, "//management-interfaces/http-interface",
                "ssl-context"));

    }

    private void verifyAliasInKeyStore(StandaloneServer server, String keyStoreName, String expectedAlias) throws OperationFailedException {
        final ModelNode res = server.execute(getReadAliasFromKeyStoreOp(keyStoreName), "Read alias");
        assertEquals(1, res.asList().size());
        assertEquals(expectedAlias, res.asList().get(0).asString());
    }

    private void verifyAliasInKeyStore(DomainServer server, String keyStoreName, String expectedAlias) throws OperationFailedException {
        final ModelNode res = server.execute(
                server.wrapInHost(getReadAliasFromKeyStoreOp(keyStoreName)), "Read alias");
        assertEquals(1, res.asList().size());
        assertEquals(expectedAlias, res.asList().get(0).asString());
    }

    protected static ModelNode getReadAliasFromKeyStoreOp(String keyStoreName) throws OperationFailedException {
        // /subsystem=elytron/key-store=application-truststore:read-aliases()
        return createEmptyOperation("read-aliases",
                PathAddress.pathAddress("subsystem", "elytron").append("key-store", keyStoreName));
    }

    private String getAttribute(Document doc, String expression, String attrName) throws XPathExpressionException {
        NodeList nodes = (NodeList) xPath.compile(expression).evaluate(
                doc, XPathConstants.NODESET);
        final Node attr = nodes.item(0).getAttributes().getNamedItem(attrName);
        return attr == null?null:attr.getNodeValue();
    }

    protected static void clearStateOf(AbstractHttpsEnableTask.Config config) {
        config.setKeystoreGeneratedForStandalone(false);
        config.setKeystoreGeneratedForDomain(false);
        config.setClientCertImportedForStandalone(false);
        config.setClientCertImportedForDomain(false);
    }
}
