From aaedacfecd1ffe308147eb7ebcb4a5b0800a6498 Mon Sep 17 00:00:00 2001 From: Zixuan Liu Date: Wed, 3 Aug 2022 20:31:11 +0800 Subject: [PATCH] [improve][authentication] Improve get the basic authentication config (#16526) Signed-off-by: Zixuan Liu (cherry picked from commit d32e1df89c4a88fe3f3a26e3ed9563d8c2a2ae21) --- conf/broker.conf | 7 ++ conf/proxy.conf | 7 ++ conf/standalone.conf | 6 ++ .../AuthenticationProviderBasic.java | 29 ++++-- .../AuthenticationProviderBasicTest.java | 90 +++++++++++++++++++ .../resources/authentication/basic/.htpasswd | 2 + 6 files changed, 135 insertions(+), 6 deletions(-) create mode 100644 pulsar-broker-common/src/test/java/org/apache/pulsar/broker/authentication/AuthenticationProviderBasicTest.java create mode 100644 pulsar-broker-common/src/test/resources/authentication/basic/.htpasswd diff --git a/conf/broker.conf b/conf/broker.conf index d2dc7da75afb4..08884a4be572e 100644 --- a/conf/broker.conf +++ b/conf/broker.conf @@ -748,6 +748,13 @@ athenzDomainNames= # When this parameter is not empty, unauthenticated users perform as anonymousUserRole anonymousUserRole= +## Configure the datasource of basic authenticate, supports the file and Base64 format. +# file: +# basicAuthConf=/path/my/.htpasswd +# use Base64 to encode the contents of .htpasswd: +# basicAuthConf=YOUR-BASE64-DATA +basicAuthConf= + ### --- Token Authentication Provider --- ### ## Symmetric key diff --git a/conf/proxy.conf b/conf/proxy.conf index d7484c8148642..8555834a13f1c 100644 --- a/conf/proxy.conf +++ b/conf/proxy.conf @@ -251,6 +251,13 @@ httpRequestsLimitEnabled=false httpRequestsMaxPerSecond=100.0 +## Configure the datasource of basic authenticate, supports the file and Base64 format. +# file: +# basicAuthConf=/path/my/.htpasswd +# use Base64 to encode the contents of .htpasswd: +# basicAuthConf=YOUR-BASE64-DATA +basicAuthConf= + ### --- Token Authentication Provider --- ### ## Symmetric key diff --git a/conf/standalone.conf b/conf/standalone.conf index f3a88879f4051..5f90ea1ce3fd6 100644 --- a/conf/standalone.conf +++ b/conf/standalone.conf @@ -491,6 +491,12 @@ athenzDomainNames= # When this parameter is not empty, unauthenticated users perform as anonymousUserRole anonymousUserRole= +## Configure the datasource of basic authenticate, supports the file and Base64 format. +# file: +# basicAuthConf=/path/my/.htpasswd +# use Base64 to encode the contents of .htpasswd: +# basicAuthConf=YOUR-BASE64-DATA +basicAuthConf= ### --- Token Authentication Provider --- ### diff --git a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderBasic.java b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderBasic.java index 631659c24b518..ff62bf60cb469 100644 --- a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderBasic.java +++ b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderBasic.java @@ -23,6 +23,8 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Base64; import java.util.HashMap; @@ -39,6 +41,7 @@ public class AuthenticationProviderBasic implements AuthenticationProvider { private static final String HTTP_HEADER_NAME = "Authorization"; private static final String CONF_SYSTEM_PROPERTY_KEY = "pulsar.auth.basic.conf"; + private static final String CONF_PULSAR_PROPERTY_KEY = "basicAuthConf"; private Map users; @Override @@ -48,14 +51,28 @@ public void close() throws IOException { @Override public void initialize(ServiceConfiguration config) throws IOException { - File confFile = new File(System.getProperty(CONF_SYSTEM_PROPERTY_KEY)); - if (!confFile.exists()) { - throw new IOException("The password auth conf file does not exist"); - } else if (!confFile.isFile()) { - throw new IOException("The path is not a file"); + String data = config.getProperties().getProperty(CONF_PULSAR_PROPERTY_KEY); + if (StringUtils.isEmpty(data)) { + data = System.getProperty(CONF_SYSTEM_PROPERTY_KEY); + } + if (StringUtils.isEmpty(data)) { + throw new IOException("No basic authentication config provided"); + } + + @Cleanup BufferedReader reader = null; + if (org.apache.commons.codec.binary.Base64.isBase64(data)) { + reader = new BufferedReader(new StringReader(new String(Base64.getDecoder().decode(data), + StandardCharsets.UTF_8))); + } else { + File confFile = new File(data); + if (!confFile.exists()) { + throw new IOException("The password auth conf file does not exist"); + } else if (!confFile.isFile()) { + throw new IOException("The path is not a file"); + } + reader = new BufferedReader(new FileReader(confFile)); } - @Cleanup BufferedReader reader = new BufferedReader(new FileReader(confFile)); users = new HashMap<>(); for (String line : reader.lines().toArray(s -> new String[s])) { List splitLine = Arrays.asList(line.split(":")); diff --git a/pulsar-broker-common/src/test/java/org/apache/pulsar/broker/authentication/AuthenticationProviderBasicTest.java b/pulsar-broker-common/src/test/java/org/apache/pulsar/broker/authentication/AuthenticationProviderBasicTest.java new file mode 100644 index 0000000000000..217d9af9e08b2 --- /dev/null +++ b/pulsar-broker-common/src/test/java/org/apache/pulsar/broker/authentication/AuthenticationProviderBasicTest.java @@ -0,0 +1,90 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.pulsar.broker.authentication; + +import com.google.common.io.Resources; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Base64; +import java.util.Properties; +import lombok.Cleanup; +import org.apache.pulsar.broker.ServiceConfiguration; +import org.apache.pulsar.common.api.AuthData; +import org.testng.annotations.Test; + +import javax.naming.AuthenticationException; + +public class AuthenticationProviderBasicTest { + private final String basicAuthConf = Resources.getResource("authentication/basic/.htpasswd").getPath(); + private final String basicAuthConfBase64 = Base64.getEncoder().encodeToString(Files.readAllBytes(Path.of(basicAuthConf))); + + public AuthenticationProviderBasicTest() throws IOException { + } + + private void testAuthenticate(AuthenticationProviderBasic provider) throws AuthenticationException { + AuthData authData = AuthData.of("superUser2:superpassword".getBytes(StandardCharsets.UTF_8)); + provider.newAuthState(authData, null, null); + } + + @Test + public void testLoadFileFromPulsarProperties() throws Exception { + @Cleanup + AuthenticationProviderBasic provider = new AuthenticationProviderBasic(); + ServiceConfiguration serviceConfiguration = new ServiceConfiguration(); + Properties properties = new Properties(); + properties.setProperty("basicAuthConf", basicAuthConf); + serviceConfiguration.setProperties(properties); + provider.initialize(serviceConfiguration); + testAuthenticate(provider); + } + + @Test + public void testLoadBase64FromPulsarProperties() throws Exception { + @Cleanup + AuthenticationProviderBasic provider = new AuthenticationProviderBasic(); + ServiceConfiguration serviceConfiguration = new ServiceConfiguration(); + Properties properties = new Properties(); + properties.setProperty("basicAuthConf", basicAuthConfBase64); + serviceConfiguration.setProperties(properties); + provider.initialize(serviceConfiguration); + testAuthenticate(provider); + } + + @Test + public void testLoadFileFromSystemProperties() throws Exception { + @Cleanup + AuthenticationProviderBasic provider = new AuthenticationProviderBasic(); + ServiceConfiguration serviceConfiguration = new ServiceConfiguration(); + System.setProperty("pulsar.auth.basic.conf", basicAuthConf); + provider.initialize(serviceConfiguration); + testAuthenticate(provider); + } + + @Test + public void testLoadBase64FromSystemProperties() throws Exception { + @Cleanup + AuthenticationProviderBasic provider = new AuthenticationProviderBasic(); + ServiceConfiguration serviceConfiguration = new ServiceConfiguration(); + System.setProperty("pulsar.auth.basic.conf", basicAuthConfBase64); + provider.initialize(serviceConfiguration); + testAuthenticate(provider); + } +} diff --git a/pulsar-broker-common/src/test/resources/authentication/basic/.htpasswd b/pulsar-broker-common/src/test/resources/authentication/basic/.htpasswd new file mode 100644 index 0000000000000..b1a099a5f0ecb --- /dev/null +++ b/pulsar-broker-common/src/test/resources/authentication/basic/.htpasswd @@ -0,0 +1,2 @@ +superUser:mQQQIsyvvKRtU +superUser2:$apr1$foobarmq$kuSZlLgOITksCkRgl57ie/