/*
 * 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.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.postinstall.task.secdom.KerberosSecurity;
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 java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;

import static org.jboss.installer.test.utils.TestServer.TARGET_PATH;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class AddKerberosSecurityDomainTest {
    private StandaloneServer standaloneServer;
    private DomainServer domainServer;
    @ClassRule
    public static TestServer testServer = new TestServer();
    @Rule
    public TemporaryFolder temporaryFolder = new TemporaryFolder();
    private SecurityDomainTask task;
    private InstallationData iData;
    private File keyTabFile;
    private File krb5ConfFile;
    private TaskPrinter printer = new NoopPrinter();

    @Before
    public void setUp() throws Exception {
        task = new SecurityDomainTask();
        iData = new InstallationData();
        standaloneServer = new StandaloneServer(TARGET_PATH.toAbsolutePath());
        domainServer = new DomainServer(TARGET_PATH.toAbsolutePath());
        iData.setTargetFolder(TARGET_PATH);

        keyTabFile = temporaryFolder.newFile("http.keytab");
        krb5ConfFile = temporaryFolder.newFile("krb5.conf");
    }

    @After
    public void tearDown() throws Exception {
        standaloneServer.close();
        domainServer.close();

        testServer.restoreConfigs();
    }

    @Test
    public void testInstallKerberosSecurityDomainInStandalone() throws ServerOperationException {
        final SecurityDomainTask.Config config = defaultConfig();
        iData.putConfig(config);
        standaloneServer.start("standalone.xml");
        try {
            assertTrue(task.applyToStandalone(iData, standaloneServer, printer));
        } finally {
            standaloneServer.shutdown();
        }
    }

    @Test
    public void testInstallKerberosSecurityDomainInDomain() throws ServerOperationException {
        final SecurityDomainTask.Config config = defaultConfig();
        iData.putConfig(config);
        domainServer.start("host.xml");
        try {
            assertTrue(task.applyToDomain(iData, domainServer, printer));
        } finally {
            domainServer.shutdown();
        }
    }

    @Test
    public void testSerializeKerberosConfig() throws Exception {
        KerberosSecurity.KerberosConfig kerberosConfig = defaultKerberosConfig();
        final SecurityDomainTask.Config config = new SecurityDomainTask.Config();
        config.setDomainName("TestSD");
        config.setKerberosConfig(defaultKerberosConfig());
        iData.putConfig(config);
        final InstallationDataSerializer serializer = new InstallationDataSerializer(new MockLanguageUtils());
        final Path outputFile = temporaryFolder.newFile().toPath();
        serializer.serialize(iData, outputFile);

        final SecurityDomainTask.Config deserializedConfig = serializer.deserialize(outputFile, Optional.empty()).getConfig(SecurityDomainTask.Config.class);
        assertEquals(kerberosConfig, deserializedConfig.getKerberosConfig());
    }


    private SecurityDomainTask.Config defaultConfig() {
        final SecurityDomainTask.Config config = new SecurityDomainTask.Config();
        iData.putConfig(config);
        config.setDomainName("TestSD");
        config.setKerberosConfig(defaultKerberosConfig());
        return config;
    }

    private KerberosSecurity.KerberosConfig defaultKerberosConfig() {
        final KerberosSecurity.KerberosConfig kerberosConfig = new KerberosSecurity.KerberosConfig();
        kerberosConfig.setKerberosSecurityFactoryName("krbSF");
        kerberosConfig.setPrincipal("HTTP/host@REALM");
        kerberosConfig.setKeyTabPath(keyTabFile.toPath());
        kerberosConfig.setMechanismNames(new String[]{"KRB5", "SPNEGO"});
        kerberosConfig.setMechanismOids(new String[]{"1.2.840.113554.1.2.2", "1.3.6.1.5.5.2"});
        kerberosConfig.setKrb5Conf(krb5ConfFile.toPath());
        kerberosConfig.setFileSystemRealmName("exampleFsRealm");
        kerberosConfig.setFileSystemRealmPath("fs-realm-users");
        kerberosConfig.setFileSystemRealmStandalonePath(Paths.get(TARGET_PATH.toAbsolutePath().toString(), File.separator, "standalone", File.separator, "configuration", File.separator, "fs-realm-users"));
        kerberosConfig.setFileSystemRealmDomainPath(Paths.get(TARGET_PATH.toAbsolutePath().toString(), File.separator, "domain", File.separator, "configuration", File.separator, "fs-realm-users"));
        kerberosConfig.setIdentityName("user1@REALM");
        kerberosConfig.setIdentityAttributeName("Roles");
        kerberosConfig.setIdentityAttributeValue(new String[]{"Admin", "Guest"});
        kerberosConfig.setSimpleRoleDecoderName("from-roles-attribute");
        kerberosConfig.setSimpleRoleDecoderAttribute("Roles");
        return kerberosConfig;
    }
}