/*
 * 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.validators;

import org.jboss.installer.core.ValidationResult;
import org.jboss.installer.postinstall.task.secdom.KerberosSecurity;
import org.jboss.installer.test.utils.MockLanguageUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import java.io.IOException;
import java.nio.file.Paths;

import static org.jboss.installer.screens.domain.KerberosSecurityDomainPanel.FILESYSTEM_REALM_NAME_LABEL;
import static org.jboss.installer.screens.domain.KerberosSecurityDomainPanel.FILESYSTEM_REALM_PATH_LABEL;
import static org.jboss.installer.screens.domain.KerberosSecurityDomainPanel.IDENTITY_ATTRIBUTE_NAME_LABEL;
import static org.jboss.installer.screens.domain.KerberosSecurityDomainPanel.IDENTITY_ATTRIBUTE_VALUE_LABEL;
import static org.jboss.installer.screens.domain.KerberosSecurityDomainPanel.IDENTITY_NAME_LABEL;
import static org.jboss.installer.screens.domain.KerberosSecurityDomainPanel.KERBEROS_SECURITY_FACTORY_NAME_LABEL;
import static org.jboss.installer.screens.domain.KerberosSecurityDomainPanel.KEYTAB_PATH_LABEL;
import static org.jboss.installer.screens.domain.KerberosSecurityDomainPanel.KRB5_CONF_FILE_LABEL;
import static org.jboss.installer.screens.domain.KerberosSecurityDomainPanel.PRINCIPAL_LABEL;
import static org.jboss.installer.screens.domain.KerberosSecurityDomainPanel.SIMPLE_ROLE_DECODER_ATTRIBUTE_LABEL;
import static org.jboss.installer.screens.domain.KerberosSecurityDomainPanel.SIMPLE_ROLE_DECODER_NAME_LABEL;
import static org.jboss.installer.validators.CertificateSecurityDomainValidator.GENERIC_VALIDATION_EMPTY_FIELD;
import static org.jboss.installer.validators.FileValidator.IS_DIRECTORY_ERROR;
import static org.jboss.installer.validators.FileValidator.NOT_ABSOLUTE_ERROR;
import static org.jboss.installer.validators.FileValidator.NOT_EXISTS_ERROR;
import static org.jboss.installer.validators.KerberosSecurityDomainValidator.UNSUPPORTED_MECHANISM_NAME_ERROR;
import static org.jboss.installer.validators.KerberosSecurityDomainValidator.UNSUPPORTED_MECHANISM_OID_ERROR;
import static org.junit.Assert.assertEquals;

public class KerberosSecurityDomainValidatorTest {

    @Rule
    public TemporaryFolder temp = new TemporaryFolder();
    private final MockLanguageUtils langUtils = new MockLanguageUtils();
    private final KerberosSecurityDomainValidator validator = new KerberosSecurityDomainValidator(langUtils);
    private KerberosSecurity.KerberosConfig config;

    @Before
    public void setUp() throws Exception {
        config = defaultConfig();
    }

    @Test
    public void testDefaultConfigOK() {
        assertEquals(ValidationResult.ok(), validator.validate(config));
    }

    @Test
    public void testEmptyKerberosSecurityFactoryName() {
        final String expectedError = langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD, langUtils.getString(KERBEROS_SECURITY_FACTORY_NAME_LABEL));
        config.setKerberosSecurityFactoryName(null);
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
    }

    @Test
    public void testEmptyPrincipal() {
        final String expectedError = langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD, langUtils.getString(PRINCIPAL_LABEL));
        config.setPrincipal(null);
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
    }

    @Test
    public void testKeyTabPathPresentExistsAndNonEmpty() {
        final String expectedError = langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD, langUtils.getString(KEYTAB_PATH_LABEL));
        config.setKeyTabPath(null);
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
        config.setKeyTabPath(Paths.get("not", "absolute", "path"));
        assertEquals(ValidationResult.error(NOT_ABSOLUTE_ERROR).getResult(), validator.validate(config).getResult());
        config.setKeyTabPath(Paths.get(temp.toString(), "nonexistent"));
        assertEquals(ValidationResult.error(NOT_EXISTS_ERROR).getResult(), validator.validate(config).getResult());
        config.setKeyTabPath(temp.getRoot().toPath());
        assertEquals(ValidationResult.error(IS_DIRECTORY_ERROR).getResult(), validator.validate(config).getResult());
    }

    @Test
    public void testMechanismNamesValueAndEmptyOK() {
        final String expectedError = langUtils.getString(UNSUPPORTED_MECHANISM_NAME_ERROR, "UNSUPPORTED");
        config.setMechanismNames(new String[]{"UNSUPPORTED"});
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
        config.setMechanismNames(new String[]{});
        assertEquals(ValidationResult.ok(), validator.validate(config));
    }

    @Test
    public void testMechanismOidsValueAndEmptyOK() {
        final String expectedError = langUtils.getString(UNSUPPORTED_MECHANISM_OID_ERROR, "1.2.3.4");
        config.setMechanismOids(new String[]{"1.2.3.4"});
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
        config.setMechanismOids(new String[]{});
        assertEquals(ValidationResult.ok(), validator.validate(config));
    }

    @Test
    public void testKrb5ConfPathPresentExistsAndNonEmpty() {
        final String expectedError = langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD, langUtils.getString(KRB5_CONF_FILE_LABEL));
        config.setKrb5Conf(null);
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
        config.setKrb5Conf(Paths.get("not", "absolute", "path"));
        assertEquals(ValidationResult.error(NOT_ABSOLUTE_ERROR).getResult(), validator.validate(config).getResult());
        config.setKrb5Conf(Paths.get(temp.toString(), "nonexistent"));
        assertEquals(ValidationResult.error(NOT_EXISTS_ERROR).getResult(), validator.validate(config).getResult());
        config.setKrb5Conf(temp.getRoot().toPath());
        assertEquals(ValidationResult.error(IS_DIRECTORY_ERROR).getResult(), validator.validate(config).getResult());
    }

    @Test
    public void testEmptyFileSystemRealmName() {
        final String expectedError = langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD, langUtils.getString(FILESYSTEM_REALM_NAME_LABEL));
        config.setFileSystemRealmName(null);
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
    }

    @Test
    public void testEmptyFileSystemRealmPathName() {
        final String expectedError = langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD, langUtils.getString(FILESYSTEM_REALM_PATH_LABEL));
        config.setFileSystemRealmPath(null);
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
    }

    @Test
    public void testEmptyIdentityName() {
        final String expectedError = langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD, langUtils.getString(IDENTITY_NAME_LABEL));
        config.setIdentityName(null);
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
    }

    @Test
    public void testEmptyIdentityAttributeName() {
        final String expectedError = langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD, langUtils.getString(IDENTITY_ATTRIBUTE_NAME_LABEL));
        config.setIdentityAttributeName(null);
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
    }

    @Test
    public void testEmptyIdentityAttributeValue() {
        final String expectedError = langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD, langUtils.getString(IDENTITY_ATTRIBUTE_VALUE_LABEL));
        config.setIdentityAttributeValue(null);
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
        config.setIdentityAttributeValue(new String[]{});
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
    }

    @Test
    public void testEmptySimpleRoleDecoderName() {
        final String expectedError = langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD, langUtils.getString(SIMPLE_ROLE_DECODER_NAME_LABEL));
        config.setSimpleRoleDecoderName(null);
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
    }

    @Test
    public void testEmptySimpleRoleDecoderAttribute() {
        final String expectedError = langUtils.getString(GENERIC_VALIDATION_EMPTY_FIELD, langUtils.getString(SIMPLE_ROLE_DECODER_ATTRIBUTE_LABEL));
        config.setSimpleRoleDecoderAttribute(null);
        assertEquals(ValidationResult.error(expectedError), validator.validate(config));
    }

    private KerberosSecurity.KerberosConfig defaultConfig() throws IOException {
        final KerberosSecurity.KerberosConfig config = new KerberosSecurity.KerberosConfig();
        config.setKerberosSecurityFactoryName("krbSF");
        config.setPrincipal("HTTP/host@REALM");
        config.setKeyTabPath(temp.newFile("http.keytab").toPath().toAbsolutePath());
        config.setMechanismNames(new String[]{"KRB5", "SPNEGO"});
        config.setMechanismOids(new String[]{"1.2.840.113554.1.2.2", "1.3.6.1.5.5.2"});
        config.setKrb5Conf(temp.newFile("krb5.conf").toPath().toAbsolutePath());
        config.setFileSystemRealmName("exampleFsRealm");
        config.setFileSystemRealmPath("fs-realm-users");
        config.setIdentityName("user1@REALM");
        config.setIdentityAttributeName("Roles");
        config.setIdentityAttributeValue(new String[]{"Admin", "Guest"});
        config.setSimpleRoleDecoderName("from-roles-attribute");
        config.setSimpleRoleDecoderAttribute("Roles");
        return config;
    }
}
