/* * 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.operation.auth; import com.google.common.collect.ImmutableMap; import io.crate.action.sql.SessionContext; import io.crate.plugin.SQLPlugin; import io.crate.test.integration.CrateUnitTest; import org.apache.commons.lang3.RandomStringUtils; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.network.InetAddresses; import org.elasticsearch.common.settings.Settings; import org.jboss.netty.channel.Channel; import org.junit.Before; import org.junit.Test; import java.net.InetAddress; import java.util.*; import java.util.concurrent.CompletableFuture; import static io.crate.operation.auth.HostBasedAuthentication.Matchers.isValidAddress; import static io.crate.operation.auth.HostBasedAuthentication.Matchers.isValidProtocol; import static io.crate.operation.auth.HostBasedAuthentication.Matchers.isValidUser; import static org.hamcrest.core.Is.is; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class HostBasedAuthenticationTest extends CrateUnitTest { private static final ImmutableMap<String, String> HBA_1 = ImmutableMap.<String, String>builder() .put("user", "crate") .put("address", "127.0.0.1") .put("method", "trust") .put("protocol", "pg") .build(); private static final ImmutableMap<String, String> HBA_2 = ImmutableMap.<String, String>builder() .put("user", "crate") .put("address", "0.0.0.0/0") .put("method", "fake") .put("protocol", "pg") .build(); private static final ImmutableMap<String, String> HBA_3 = ImmutableMap.<String, String>builder() .put("address", "127.0.0.1") .put("method", "md5") .put("protocol", "pg") .build(); private static final InetAddress LOCALHOST = InetAddresses.forString("127.0.0.1"); private HostBasedAuthentication authService; @Before private void setUpTest() { Settings settings = Settings.builder() .put(AuthenticationProvider.AUTH_HOST_BASED_ENABLED_SETTING.getKey(), true) .build(); authService = new HostBasedAuthentication(settings); } private static ClusterService createClusterService(Settings settings){ SQLPlugin sqlPlugin = new SQLPlugin(Settings.EMPTY); Set<Setting<?>> cSettings = new HashSet<>(); cSettings.addAll(ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); cSettings.addAll(sqlPlugin.getSettings()); ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, cSettings); ClusterService clusterService = mock(ClusterService.class); when(clusterService.getSettings()).thenReturn(settings); when(clusterService.getClusterSettings()).thenReturn(clusterSettings); return clusterService; } @SafeVarargs private static Map<String, Map<String, String>> createHbaConf(Map<String, String>... entries) { ImmutableMap.Builder<String, Map<String, String>> builder = ImmutableMap.builder(); int idx = 0; for (Map<String, String> entry : entries) { builder.put(String.valueOf(idx), entry); idx++; } return builder.build(); } @Test public void testEnableAuthentication() throws Exception { Authentication authService = new HostBasedAuthentication(Settings.EMPTY); assertFalse(authService.enabled()); Settings settings = Settings.builder() .put(AuthenticationProvider.AUTH_HOST_BASED_ENABLED_SETTING.getKey(), true) .build(); authService = new HostBasedAuthentication(settings); assertTrue(authService.enabled()); } @Test public void testMissingUserOrAddress() throws Exception { authService.updateHbaConfig(Collections.emptyMap()); AuthenticationMethod method; method = authService.resolveAuthenticationType(null, LOCALHOST, HbaProtocol.POSTGRES); assertNull(method); method = authService.resolveAuthenticationType("crate", null, HbaProtocol.POSTGRES); assertNull(method); } @Test public void testEmptyHbaConf() throws Exception { authService.updateHbaConfig(Collections.emptyMap()); AuthenticationMethod method = authService.resolveAuthenticationType("crate", LOCALHOST, HbaProtocol.POSTGRES); assertNull(method); } @Test public void testResolveAuthMethod() throws Exception { AuthenticationMethod noopAuthMethod = new AuthenticationMethod() { @Override public CompletableFuture<Boolean> pgAuthenticate(Channel channel, SessionContext session) { return null; } @Override public String name() { return "trust"; } }; authService.registerAuthMethod(noopAuthMethod.name(), () -> noopAuthMethod); authService.updateHbaConfig(createHbaConf(HBA_1)); AuthenticationMethod method = authService.resolveAuthenticationType("crate", LOCALHOST, HbaProtocol.POSTGRES); assertThat(method, is(noopAuthMethod)); } @Test public void testFilterEntriesSimple() throws Exception { authService.updateHbaConfig(createHbaConf(HBA_1)); Optional entry; entry = authService.getEntry("crate", LOCALHOST, HbaProtocol.POSTGRES); assertThat(entry.isPresent(), is(true)); entry = authService.getEntry("cr8", LOCALHOST, HbaProtocol.POSTGRES); assertThat(entry.isPresent(), is(false)); entry = authService.getEntry("crate", InetAddresses.forString("10.0.0.1"), HbaProtocol.POSTGRES); assertThat(entry.isPresent(), is(false)); } @Test public void testFilterEntriesCIDR() throws Exception { authService.updateHbaConfig(createHbaConf(HBA_2, HBA_3)); Optional<Map.Entry<String, Map<String, String>>> entry; entry = authService.getEntry("crate", InetAddresses.forString("123.45.67.89"), HbaProtocol.POSTGRES); assertTrue(entry.isPresent()); assertThat(entry.get().getValue().get("method"), is("fake")); entry = authService.getEntry("cr8", InetAddresses.forString("127.0.0.1"), HbaProtocol.POSTGRES); assertTrue(entry.isPresent()); assertThat(entry.get().getValue().get("method"), is("md5")); entry = authService.getEntry("cr8", InetAddresses.forString("123.45.67.89"), HbaProtocol.POSTGRES); assertThat(entry.isPresent(), is(false)); } @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", HbaProtocol.POSTGRES)); assertFalse(isValidProtocol("http", HbaProtocol.POSTGRES)); assertTrue(isValidProtocol(null, HbaProtocol.POSTGRES)); } @Test public void testMatchAddress() throws Exception { // matches Map.Entry<String, Map<String, String>> entry = new HashMap.SimpleEntry<>( "0", Collections.singletonMap("address", "10.0.1.100") ); assertTrue(isValidAddress(entry, InetAddresses.forString("10.0.1.100"))); assertFalse(isValidAddress(entry, InetAddresses.forString("10.0.1.99"))); assertFalse(isValidAddress(entry, InetAddresses.forString("10.0.1.101"))); entry = new HashMap.SimpleEntry<>( "0", Collections.singletonMap("address", "10.0.1.0/24") // 10.0.1.0 -- 10.0.1.255 ); assertTrue(isValidAddress(entry, InetAddresses.forString("10.0.1.0"))); assertTrue(isValidAddress(entry, InetAddresses.forString("10.0.1.255"))); assertFalse(isValidAddress(entry, InetAddresses.forString("10.0.0.255"))); assertFalse(isValidAddress(entry, InetAddresses.forString("10.0.2.0"))); entry = new HashMap.SimpleEntry<>( "0", Collections.emptyMap() // key "address" is missing ); assertTrue(isValidAddress(entry, 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("auth.host_based.config", "0", new String[]{"user", "address", "method", "protocol"}, new String[]{"crate", "127.0.0.1", "trust", "pg"}) .put("auth.host_based.config", "1", new String[]{"user", "address", "method", "protocol"}, new String[]{"crate", "0.0.0.0/0", "fake", "pg"}) .put("auth.host_based.config", "2", new String[]{}, new String[]{}) // ignored because empty .build(); HostBasedAuthentication authService = new HostBasedAuthentication(settings); assertThat(authService.hbaConf(), is(createHbaConf(HBA_1, HBA_2))); } }