/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License;
 * you may not use this file except in compliance with the Elastic License.
 */
package org.elasticsearch.integration.ldap;

import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.junit.annotations.Network;
import org.junit.BeforeClass;

/**
 * This tests that configurations that contain two AD realms work correctly.
 * The required behaviour is that users from both realms (directory servers) can be authenticated using
 * just their userid (the AuthenticationService tries them in order)
 */
@Network
public class MultipleAdRealmTests extends AbstractAdLdapRealmTestCase {

    private static RealmConfig secondaryRealmConfig;

    @BeforeClass
    public static void setupSecondaryRealm() {
        // Pick a secondary realm that has the inverse value for 'loginWithCommonName' compare with the primary realm
        final List<RealmConfig> configs = new ArrayList<>();
        for (RealmConfig config : RealmConfig.values()) {
            if (config.loginWithCommonName != AbstractAdLdapRealmTestCase.realmConfig.loginWithCommonName) {
                configs.add(config);
            }
        }
        secondaryRealmConfig = randomFrom(configs);
        ESLoggerFactory.getLogger("test")
                .info("running test with secondary realm configuration [{}], with direct group to role mapping [{}]. Settings [{}]",
                        secondaryRealmConfig, secondaryRealmConfig.mapGroupsAsRoles, secondaryRealmConfig.settings.getAsMap());
    }

    @Override
    protected Settings nodeSettings(int nodeOrdinal) {
        Settings.Builder builder = Settings.builder();
        builder.put(super.nodeSettings(nodeOrdinal));

        Path store = getDataPath(TESTNODE_KEYSTORE);
        final Settings secondarySettings = super.buildRealmSettings(secondaryRealmConfig, store);
        secondarySettings.getAsMap().forEach((name, value) -> {
            name = name.replace(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL, XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + "2");
            builder.put(name, value);
        });

        return builder.build();
    }

    /**
     * Test that both realms support user login. Implementation wise, this means that if the first realm reject the authentication attempt,
     * then the second realm will be tried.
     * Because one realm is using "common name" (cn) for login, and the other uses the "userid" (sAMAccountName) [see
     * {@link #setupSecondaryRealm()}], this is simply a matter of checking that we can authenticate with both identifiers.
     */
    public void testCanAuthenticateAgainstBothRealms() throws IOException {
        assertAccessAllowed("Natasha Romanoff", "avengers");
        assertAccessAllowed("blackwidow", "avengers");
    }

}
