/** * Copyright 2016 Yahoo Inc. * * 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 com.yahoo.pulsar.client.api; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import java.net.URI; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import javax.ws.rs.InternalServerErrorException; import org.junit.Assert; import org.mockito.Mockito; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.yahoo.pulsar.broker.authentication.AuthenticationProviderTls; import com.yahoo.pulsar.client.admin.PulsarAdmin; import com.yahoo.pulsar.client.admin.PulsarAdminException; import com.yahoo.pulsar.client.impl.auth.AuthenticationTls; import com.yahoo.pulsar.common.policies.data.ClusterData; import com.yahoo.pulsar.common.policies.data.PropertyAdmin; public class AuthenticatedProducerConsumerTest extends ProducerConsumerBase { private static final Logger log = LoggerFactory.getLogger(AuthenticatedProducerConsumerTest.class); private final String TLS_TRUST_CERT_FILE_PATH = "./src/test/resources/authentication/tls/cacert.pem"; private final String TLS_SERVER_CERT_FILE_PATH = "./src/test/resources/authentication/tls/broker-cert.pem"; private final String TLS_SERVER_KEY_FILE_PATH = "./src/test/resources/authentication/tls/broker-key.pem"; private final String TLS_CLIENT_CERT_FILE_PATH = "./src/test/resources/authentication/tls/client-cert.pem"; private final String TLS_CLIENT_KEY_FILE_PATH = "./src/test/resources/authentication/tls/client-key.pem"; @BeforeMethod @Override protected void setup() throws Exception { conf.setAuthenticationEnabled(true); conf.setAuthorizationEnabled(true); conf.setTlsEnabled(true); conf.setTlsTrustCertsFilePath(TLS_TRUST_CERT_FILE_PATH); conf.setTlsCertificateFilePath(TLS_SERVER_CERT_FILE_PATH); conf.setTlsKeyFilePath(TLS_SERVER_KEY_FILE_PATH); conf.setTlsAllowInsecureConnection(true); Set<String> superUserRoles = new HashSet<>(); superUserRoles.add("localhost"); superUserRoles.add("superUser"); conf.setSuperUserRoles(superUserRoles); conf.setBrokerClientAuthenticationPlugin(AuthenticationTls.class.getName()); conf.setBrokerClientAuthenticationParameters( "tlsCertFile:" + TLS_CLIENT_CERT_FILE_PATH + "," + "tlsKeyFile:" + TLS_SERVER_KEY_FILE_PATH); Set<String> providers = new HashSet<>(); providers.add(AuthenticationProviderTls.class.getName()); conf.setAuthenticationProviders(providers); conf.setClusterName("use"); super.init(); } protected final void internalSetup(Authentication auth) throws Exception { com.yahoo.pulsar.client.api.ClientConfiguration clientConf = new com.yahoo.pulsar.client.api.ClientConfiguration(); clientConf.setStatsInterval(0, TimeUnit.SECONDS); clientConf.setTlsTrustCertsFilePath(TLS_TRUST_CERT_FILE_PATH); clientConf.setTlsAllowInsecureConnection(true); clientConf.setAuthentication(auth); clientConf.setUseTls(true); admin = spy(new PulsarAdmin(brokerUrlTls, clientConf)); String lookupUrl = new URI("pulsar+ssl://localhost:" + BROKER_PORT_TLS).toString(); pulsarClient = PulsarClient.create(lookupUrl, clientConf); } @AfterMethod @Override protected void cleanup() throws Exception { super.internalCleanup(); } @DataProvider(name = "batch") public Object[][] codecProvider() { return new Object[][] { { 0 }, { 1000 } }; } @Test(dataProvider = "batch") public void testTlsSyncProducerAndConsumer(int batchMessageDelayMs) throws Exception { log.info("-- Starting {} test --", methodName); Map<String, String> authParams = new HashMap<>(); authParams.put("tlsCertFile", TLS_CLIENT_CERT_FILE_PATH); authParams.put("tlsKeyFile", TLS_CLIENT_KEY_FILE_PATH); Authentication authTls = new AuthenticationTls(); authTls.configure(authParams); internalSetup(authTls); admin.clusters().createCluster("use", new ClusterData(brokerUrl.toString(), brokerUrlTls.toString(), "pulsar://localhost:" + BROKER_PORT, "pulsar+ssl://localhost:" + BROKER_PORT_TLS)); admin.properties().createProperty("my-property", new PropertyAdmin(Lists.newArrayList("appid1", "appid2"), Sets.newHashSet("use"))); admin.namespaces().createNamespace("my-property/use/my-ns"); ConsumerConfiguration conf = new ConsumerConfiguration(); conf.setSubscriptionType(SubscriptionType.Exclusive); Consumer consumer = pulsarClient.subscribe("persistent://my-property/use/my-ns/my-topic1", "my-subscriber-name", conf); ProducerConfiguration producerConf = new ProducerConfiguration(); if (batchMessageDelayMs != 0) { producerConf.setBatchingEnabled(true); producerConf.setBatchingMaxPublishDelay(batchMessageDelayMs, TimeUnit.MILLISECONDS); producerConf.setBatchingMaxMessages(5); } Producer producer = pulsarClient.createProducer("persistent://my-property/use/my-ns/my-topic1", producerConf); for (int i = 0; i < 10; i++) { String message = "my-message-" + i; producer.send(message.getBytes()); } Message msg = null; Set<String> messageSet = Sets.newHashSet(); for (int i = 0; i < 10; i++) { msg = consumer.receive(5, TimeUnit.SECONDS); String receivedMessage = new String(msg.getData()); log.debug("Received message: [{}]", receivedMessage); String expectedMessage = "my-message-" + i; testMessageOrderAndDuplicates(messageSet, receivedMessage, expectedMessage); } // Acknowledge the consumption of all messages at once consumer.acknowledgeCumulative(msg); consumer.close(); log.info("-- Exiting {} test --", methodName); } /** * Verifies: on 500 server error, broker invalidates session and client receives 500 correctly. * * @throws Exception */ @Test public void testAuthemticationFilterNegative() throws Exception { log.info("-- Starting {} test --", methodName); Map<String, String> authParams = new HashMap<>(); authParams.put("tlsCertFile", TLS_CLIENT_CERT_FILE_PATH); authParams.put("tlsKeyFile", TLS_CLIENT_KEY_FILE_PATH); Authentication authTls = new AuthenticationTls(); authTls.configure(authParams); internalSetup(authTls); final String cluster = "use"; final ClusterData clusterData = new ClusterData(brokerUrl.toString(), brokerUrlTls.toString(), "pulsar://localhost:" + BROKER_PORT, "pulsar+ssl://localhost:" + BROKER_PORT_TLS); // this will cause NPE and it should throw 500 doReturn(null).when(pulsar).getGlobalZkCache(); try { admin.clusters().createCluster(cluster, clusterData); } catch (PulsarAdminException e) { Assert.assertTrue(e.getCause() instanceof InternalServerErrorException); } log.info("-- Exiting {} test --", methodName); } /** * verifies that topicLookup/PartitionMetadataLookup gives InternalServerError(500) instead 401(auth_failed) on * unknown-exception failure * * @throws Exception */ @Test public void testInternalServerExceptionOnLookup() throws Exception { log.info("-- Starting {} test --", methodName); Map<String, String> authParams = new HashMap<>(); authParams.put("tlsCertFile", TLS_CLIENT_CERT_FILE_PATH); authParams.put("tlsKeyFile", TLS_CLIENT_KEY_FILE_PATH); Authentication authTls = new AuthenticationTls(); authTls.configure(authParams); internalSetup(authTls); admin.clusters().createCluster("use", new ClusterData(brokerUrl.toString(), brokerUrlTls.toString(), "pulsar://localhost:" + BROKER_PORT, "pulsar+ssl://localhost:" + BROKER_PORT_TLS)); admin.properties().createProperty("my-property", new PropertyAdmin(Lists.newArrayList("appid1", "appid2"), Sets.newHashSet("use"))); String namespace = "my-property/use/my-ns"; admin.namespaces().createNamespace(namespace); String destination = "persistent://" + namespace + "1/topic1"; // this will cause NPE and it should throw 500 mockZookKeeper.shutdown(); pulsar.getConfiguration().setSuperUserRoles(Sets.newHashSet()); try { admin.persistentTopics().getPartitionedTopicMetadata(destination); } catch (PulsarAdminException e) { Assert.assertTrue(e.getCause() instanceof InternalServerErrorException); } try { admin.lookups().lookupDestination(destination); } catch (PulsarAdminException e) { Assert.assertTrue(e.getCause() instanceof InternalServerErrorException); } } }