io.crate.auth.HostBasedAuthenticationTest.java Source code

Java tutorial

Introduction

Here is the source code for io.crate.auth.HostBasedAuthenticationTest.java

Source

/*
 * This file is part of a module with proprietary Enterprise Features.
 *
 * Licensed to Crate.io Inc. ("Crate.io") under one or more contributor
 * license agreements.  See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.
 *
 * Unauthorized copying of this file, via any medium is strictly prohibited.
 *
 * To use this file, Crate.io must have given you permission to enable and
 * use such Enterprise Features and you must have a valid Enterprise or
 * Subscription Agreement with Crate.io.  If you enable or use the Enterprise
 * Features, you represent and warrant that you have a valid Enterprise or
 * Subscription Agreement with Crate.io.  Your use of the Enterprise Features
 * if governed by the terms and conditions of your Enterprise or Subscription
 * Agreement with Crate.io.
 */

package io.crate.auth;

import io.crate.protocols.postgres.ConnectionProperties;
import io.crate.test.integration.CrateUnitTest;
import io.netty.buffer.ByteBufAllocator;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import org.apache.commons.lang3.RandomStringUtils;
import org.elasticsearch.common.network.InetAddresses;
import org.elasticsearch.common.settings.Settings;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;

import javax.net.ssl.SSLSession;
import java.net.InetAddress;
import java.security.cert.Certificate;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import static io.crate.auth.HostBasedAuthentication.Matchers.isValidAddress;
import static io.crate.auth.HostBasedAuthentication.Matchers.isValidProtocol;
import static io.crate.auth.HostBasedAuthentication.Matchers.isValidUser;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.core.Is.is;
import static org.mockito.Mockito.when;

public class HostBasedAuthenticationTest extends CrateUnitTest {

    private static final Settings HBA_1 = Settings.builder().put("auth.host_based.config.1.user", "crate")
            .put("auth.host_based.config.1.address", "127.0.0.1").put("auth.host_based.config.1.method", "trust")
            .put("auth.host_based.config.1.protocol", "pg").build();

    private static final Settings HBA_2 = Settings.builder().put("auth.host_based.config.2.user", "crate")
            .put("auth.host_based.config.2.address", "0.0.0.0/0").put("auth.host_based.config.2.method", "fake")
            .put("auth.host_based.config.2.protocol", "pg").build();

    private static final Settings HBA_3 = Settings.builder().put("auth.host_based.config.3.address", "127.0.0.1")
            .put("auth.host_based.config.3.method", "md5").put("auth.host_based.config.3.protocol", "pg").build();

    private static final Settings HBA_4 = Settings.builder().put("auth.host_based.config.4.address", "_local_")
            .build();

    private static final InetAddress LOCALHOST = InetAddresses.forString("127.0.0.1");

    private SSLSession sslSession;

    @Before
    private void setUpTest() throws Exception {
        SelfSignedCertificate ssc = new SelfSignedCertificate();
        SslHandler sslHandler = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
                .trustManager(InsecureTrustManagerFactory.INSTANCE).startTls(false).build()
                .newHandler(ByteBufAllocator.DEFAULT);
        sslSession = sslHandler.engine().getSession();
    }

    @Test
    public void testMissingUserOrAddress() {
        HostBasedAuthentication authService = new HostBasedAuthentication(Settings.EMPTY, null);
        AuthenticationMethod method;
        method = authService.resolveAuthenticationType(null,
                new ConnectionProperties(LOCALHOST, Protocol.POSTGRES, null));
        assertNull(method);
        method = authService.resolveAuthenticationType("crate",
                new ConnectionProperties(null, Protocol.POSTGRES, null));
        assertNull(method);
    }

    @Test
    public void testEmptyHbaConf() {
        HostBasedAuthentication authService = new HostBasedAuthentication(Settings.EMPTY, null);
        AuthenticationMethod method = authService.resolveAuthenticationType("crate",
                new ConnectionProperties(LOCALHOST, Protocol.POSTGRES, null));
        assertNull(method);
    }

    @Test
    public void testResolveAuthMethod() {
        HostBasedAuthentication authService = new HostBasedAuthentication(HBA_1, null);
        AuthenticationMethod method = authService.resolveAuthenticationType("crate",
                new ConnectionProperties(LOCALHOST, Protocol.POSTGRES, null));
        assertThat(method, instanceOf(TrustAuthenticationMethod.class));
    }

    @Test
    public void testFilterEntriesSimple() {
        HostBasedAuthentication authService = new HostBasedAuthentication(HBA_1, null);
        Optional entry;

        entry = authService.getEntry("crate", new ConnectionProperties(LOCALHOST, Protocol.POSTGRES, null));
        assertThat(entry.isPresent(), is(true));

        entry = authService.getEntry("cr8", new ConnectionProperties(LOCALHOST, Protocol.POSTGRES, null));
        assertThat(entry.isPresent(), is(false));

        entry = authService.getEntry("crate",
                new ConnectionProperties(InetAddresses.forString("10.0.0.1"), Protocol.POSTGRES, null));
        assertThat(entry.isPresent(), is(false));
    }

    @Test
    public void testFilterEntriesCIDR() {
        Settings settings = Settings.builder().put(HBA_2).put(HBA_3).build();
        HostBasedAuthentication authService = new HostBasedAuthentication(settings, null);

        Optional<Map.Entry<String, Map<String, String>>> entry;

        entry = authService.getEntry("crate",
                new ConnectionProperties(InetAddresses.forString("123.45.67.89"), Protocol.POSTGRES, null));
        assertTrue(entry.isPresent());
        assertThat(entry.get().getValue().get("method"), is("fake"));

        entry = authService.getEntry("cr8",
                new ConnectionProperties(InetAddresses.forString("127.0.0.1"), Protocol.POSTGRES, null));
        assertTrue(entry.isPresent());
        assertThat(entry.get().getValue().get("method"), is("md5"));

        entry = authService.getEntry("cr8",
                new ConnectionProperties(InetAddresses.forString("123.45.67.89"), Protocol.POSTGRES, null));
        assertThat(entry.isPresent(), is(false));
    }

    @Test
    public void testLocalhostMatchesBothIpv4AndIpv6() {
        HostBasedAuthentication authService = new HostBasedAuthentication(HBA_4, null);

        Optional<Map.Entry<String, Map<String, String>>> entry;
        entry = authService.getEntry("crate",
                new ConnectionProperties(InetAddresses.forString("127.0.0.1"), Protocol.POSTGRES, null));
        assertTrue(entry.isPresent());
        entry = authService.getEntry("crate",
                new ConnectionProperties(InetAddresses.forString("::1"), Protocol.POSTGRES, null));
        assertTrue(entry.isPresent());
    }

    @Test
    public void testMatchUser() throws Exception {
        // only "crate" matches
        Map.Entry<String, Map<String, String>> entry = new HashMap.SimpleEntry<>("0",
                Collections.singletonMap("user", "crate"));
        assertTrue(isValidUser(entry, "crate"));
        assertFalse(isValidUser(entry, "postgres"));

        // any user matches
        entry = new HashMap.SimpleEntry<>("0", Collections.emptyMap() // key "user" not present in map
        );
        assertTrue(isValidUser(entry, RandomStringUtils.random(8)));
    }

    @Test
    public void testMatchProtocol() throws Exception {
        assertTrue(isValidProtocol("pg", Protocol.POSTGRES));
        assertFalse(isValidProtocol("http", Protocol.POSTGRES));
        assertTrue(isValidProtocol(null, Protocol.POSTGRES));
    }

    @Test
    public void testMatchAddress() throws Exception {
        String hbaAddress = "10.0.1.100";
        assertTrue(isValidAddress(hbaAddress, InetAddresses.forString("10.0.1.100")));
        assertFalse(isValidAddress(hbaAddress, InetAddresses.forString("10.0.1.99")));
        assertFalse(isValidAddress(hbaAddress, InetAddresses.forString("10.0.1.101")));

        hbaAddress = "10.0.1.0/24"; // 10.0.1.0 -- 10.0.1.255
        assertTrue(isValidAddress(hbaAddress, InetAddresses.forString("10.0.1.0")));
        assertTrue(isValidAddress(hbaAddress, InetAddresses.forString("10.0.1.255")));
        assertFalse(isValidAddress(hbaAddress, InetAddresses.forString("10.0.0.255")));
        assertFalse(isValidAddress(hbaAddress, InetAddresses.forString("10.0.2.0")));

        assertTrue(isValidAddress(null, InetAddresses.forString(
                String.format("%s.%s.%s.%s", randomInt(255), randomInt(255), randomInt(255), randomInt(255)))));
    }

    @Test
    public void testConvertSettingsToConf() throws Exception {
        Settings settings = Settings.builder().put("auth.host_based.enabled", true).put(HBA_1).put(HBA_2)
                .put("auth.host_based.config", "3", new String[] {}, new String[] {}) // ignored because empty
                .build();

        HostBasedAuthentication authService = new HostBasedAuthentication(settings, null);
        Settings confirmSettings = Settings.builder().put(HBA_1).put(HBA_2).build();
        assertThat(authService.hbaConf(), is(authService.convertHbaSettingsToHbaConf(confirmSettings)));
    }

    @Test
    public void testPSQLSslOption() {
        Settings sslConfig;
        HostBasedAuthentication authService;

        sslConfig = Settings.builder().put(HBA_1).put("auth.host_based.config.1." + HostBasedAuthentication.SSL.KEY,
                HostBasedAuthentication.SSL.OPTIONAL.VALUE).build();
        authService = new HostBasedAuthentication(sslConfig, null);
        assertThat(authService.getEntry("crate", new ConnectionProperties(LOCALHOST, Protocol.POSTGRES, null)),
                not(Optional.empty()));
        assertThat(
                authService.getEntry("crate", new ConnectionProperties(LOCALHOST, Protocol.POSTGRES, sslSession)),
                not(Optional.empty()));

        sslConfig = Settings.builder().put(HBA_1).put("auth.host_based.config.1." + HostBasedAuthentication.SSL.KEY,
                HostBasedAuthentication.SSL.REQUIRED.VALUE).build();
        authService = new HostBasedAuthentication(sslConfig, null);
        assertThat(authService.getEntry("crate", new ConnectionProperties(LOCALHOST, Protocol.POSTGRES, null)),
                is(Optional.empty()));
        assertThat(
                authService.getEntry("crate", new ConnectionProperties(LOCALHOST, Protocol.POSTGRES, sslSession)),
                not(Optional.empty()));

        sslConfig = Settings.builder().put(HBA_1).put("auth.host_based.config.1." + HostBasedAuthentication.SSL.KEY,
                HostBasedAuthentication.SSL.NEVER.VALUE).build();
        authService = new HostBasedAuthentication(sslConfig, null);
        assertThat(authService.getEntry("crate", new ConnectionProperties(LOCALHOST, Protocol.POSTGRES, null)),
                not(Optional.empty()));
        assertThat(
                authService.getEntry("crate", new ConnectionProperties(LOCALHOST, Protocol.POSTGRES, sslSession)),
                is(Optional.empty()));
    }

    @Test
    public void testHttpSSLOption() throws Exception {
        Settings baseConfig = Settings.builder().put(HBA_1)
                .put("auth.host_based.config.1." + HostBasedAuthentication.KEY_PROTOCOL, "http").build();

        SSLSession sslSession = Mockito.mock(SSLSession.class);
        when(sslSession.getPeerCertificates()).thenReturn(new Certificate[0]);
        ConnectionProperties sslConnProperties = new ConnectionProperties(LOCALHOST, Protocol.HTTP, sslSession);
        ConnectionProperties noSslConnProperties = new ConnectionProperties(LOCALHOST, Protocol.HTTP, null);

        Settings sslConfig;
        HostBasedAuthentication authService;

        sslConfig = Settings.builder().put(baseConfig)
                .put("auth.host_based.config.1." + HostBasedAuthentication.SSL.KEY,
                        HostBasedAuthentication.SSL.OPTIONAL.VALUE)
                .build();
        authService = new HostBasedAuthentication(sslConfig, null);
        assertThat(authService.getEntry("crate", noSslConnProperties), not(Optional.empty()));
        assertThat(authService.getEntry("crate", sslConnProperties), not(Optional.empty()));

        sslConfig = Settings.builder().put(baseConfig)
                .put("auth.host_based.config.1." + HostBasedAuthentication.SSL.KEY,
                        HostBasedAuthentication.SSL.REQUIRED.VALUE)
                .build();
        authService = new HostBasedAuthentication(sslConfig, null);
        assertThat(authService.getEntry("crate", noSslConnProperties), is(Optional.empty()));
        assertThat(authService.getEntry("crate", sslConnProperties), not(Optional.empty()));

        sslConfig = Settings.builder().put(baseConfig)
                .put("auth.host_based.config.1." + HostBasedAuthentication.SSL.KEY,
                        HostBasedAuthentication.SSL.NEVER.VALUE)
                .build();
        authService = new HostBasedAuthentication(sslConfig, null);
        assertThat(authService.getEntry("crate", noSslConnProperties), not(Optional.empty()));
        assertThat(authService.getEntry("crate", sslConnProperties), is(Optional.empty()));
    }

    public void testKeyOrderIsRespectedInHbaConfig() {
        Settings first = Settings.builder().put("auth.host_based.config.1.method", "trust")
                .put("auth.host_based.config.1.protocol", "pg").build();
        Settings second = Settings.builder().put("auth.host_based.config.2.method", "cert")
                .put("auth.host_based.config.2.protocol", "http").build();

        // add in reverse order to test natural order of keys in config
        Settings settings = Settings.builder().put(second).put(first).build();
        HostBasedAuthentication hba = new HostBasedAuthentication(settings, null);

        AuthenticationMethod authMethod = hba.resolveAuthenticationType("crate",
                new ConnectionProperties(InetAddresses.forString("1.2.3.4"), Protocol.POSTGRES, null));
        assertThat(authMethod, instanceOf(TrustAuthenticationMethod.class));

        AuthenticationMethod authMethod2 = hba.resolveAuthenticationType("crate",
                new ConnectionProperties(InetAddresses.forString("1.2.3.4"), Protocol.HTTP, null));
        assertThat(authMethod2, instanceOf(ClientCertAuth.class));
    }
}