You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by wu...@apache.org on 2022/11/16 02:55:27 UTC

[ambari] branch trunk updated: AMBARI-25409: Support basic auth for repositories (#3504)

This is an automated email from the ASF dual-hosted git repository.

wuzhiguo pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ambari.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 56bb9703bf AMBARI-25409: Support basic auth for repositories (#3504)
56bb9703bf is described below

commit 56bb9703bf1a87aee1a09a1b11877fcbe1630ad8
Author: Zhiguo Wu <wu...@apache.org>
AuthorDate: Wed Nov 16 10:55:21 2022 +0800

    AMBARI-25409: Support basic auth for repositories (#3504)
---
 .../ambari/server/agent/CommandRepository.java     |  3 +-
 .../controller/AmbariManagementControllerImpl.java |  4 +-
 .../server/controller/RepositoryRequest.java       |  4 +-
 .../internal/RepositoryResourceProvider.java       | 53 +++++++++++----------
 .../RepositoryVersionResourceProvider.java         |  4 +-
 .../controller/internal/URLStreamProvider.java     | 35 +++++++++-----
 .../stack/upgrade/RepositoryVersionHelper.java     | 51 --------------------
 .../apache/ambari/server/state/RepositoryInfo.java |  3 +-
 .../ambari/server/utils/URLCredentialsHider.java   | 55 ++++++++++++++++++++++
 .../controller/internal/URLStreamProviderTest.java | 13 +++--
 .../server/utils/URLCredentialsHiderTest.java      | 41 ++++++++++++++++
 11 files changed, 168 insertions(+), 98 deletions(-)

diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/CommandRepository.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/CommandRepository.java
index 7852398328..ed5d476e74 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/CommandRepository.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/CommandRepository.java
@@ -27,6 +27,7 @@ import org.apache.ambari.annotations.ExperimentalFeature;
 import org.apache.ambari.server.orm.entities.RepoDefinitionEntity;
 import org.apache.ambari.server.state.RepositoryInfo;
 import org.apache.ambari.server.state.stack.RepoTag;
+import org.apache.ambari.server.utils.URLCredentialsHider;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.builder.ToStringBuilder;
 
@@ -354,7 +355,7 @@ public class CommandRepository {
           .append("distribution", m_distribution)
           .append("components", m_components)
           .append("id", m_repoId)
-          .append("baseUrl", m_baseUrl)
+          .append("baseUrl", URLCredentialsHider.hideCredentials(m_baseUrl))
           .append("applicableServices", (m_applicableServices != null? StringUtils.join(m_applicableServices, ",") : ""))
           .toString();
     }
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index 16f0275791..956439b900 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -248,6 +248,7 @@ import org.apache.ambari.server.topology.STOMPComponentsDeleteHandler;
 import org.apache.ambari.server.topology.Setting;
 import org.apache.ambari.server.utils.SecretReference;
 import org.apache.ambari.server.utils.StageUtils;
+import org.apache.ambari.server.utils.URLCredentialsHider;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.collections.MapUtils;
 import org.apache.commons.io.IOUtils;
@@ -4604,7 +4605,8 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
           IOUtils.readLines(usp.readFrom(spec));
         } catch (IOException ioe) {
           e = ioe;
-          errorMessage = "Could not access base url . " + request.getBaseUrl() + " . ";
+          errorMessage = String.format("Could not access base url '%s'",
+                                       URLCredentialsHider.hideCredentials(request.getBaseUrl()));
           if (LOG.isDebugEnabled()) {
             errorMessage += ioe;
           } else {
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryRequest.java
index 1f6ab5b933..5aed41ef90 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryRequest.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryRequest.java
@@ -18,6 +18,8 @@
 
 package org.apache.ambari.server.controller;
 
+import org.apache.ambari.server.utils.URLCredentialsHider;
+
 public class RepositoryRequest extends OperatingSystemRequest {
 
   private String repoId;
@@ -103,7 +105,7 @@ public class RepositoryRequest extends OperatingSystemRequest {
 
   @Override
   public String toString() {
-    return "RepositoryRequest [repoId=" + repoId + ", baseUrl=" + baseUrl
+    return "RepositoryRequest [repoId=" + repoId + ", baseUrl=" + URLCredentialsHider.hideCredentials(baseUrl)
         + ", verify=" + verify + ", getOsType()=" + getOsType()
         + ", getRepositoryVersionId()=" + getRepositoryVersionId()
         + ", getStackVersion()=" + getStackVersion() + ", getStackName()="
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryResourceProvider.java
index c09b45cbe3..48585db72d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryResourceProvider.java
@@ -43,6 +43,7 @@ import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.utils.URLCredentialsHider;
 import org.apache.commons.lang.BooleanUtils;
 
 import com.google.common.collect.ImmutableMap;
@@ -167,35 +168,35 @@ public class RepositoryResourceProvider extends AbstractControllerResourceProvid
     Set<Resource> resources = new HashSet<>();
 
     for (RepositoryResponse response : responses) {
-        Resource resource = new ResourceImpl(Resource.Type.Repository);
-
-        setResourceProperty(resource, REPOSITORY_STACK_NAME_PROPERTY_ID, response.getStackName(), requestedIds);
-        setResourceProperty(resource, REPOSITORY_STACK_VERSION_PROPERTY_ID, response.getStackVersion(), requestedIds);
-        setResourceProperty(resource, REPOSITORY_REPO_NAME_PROPERTY_ID, response.getRepoName(), requestedIds);
-        setResourceProperty(resource, REPOSITORY_DISTRIBUTION_PROPERTY_ID, response.getDistribution(), requestedIds);
-        setResourceProperty(resource, REPOSITORY_COMPONENTS_PROPERTY_ID, response.getComponents(), requestedIds);
-        setResourceProperty(resource, REPOSITORY_BASE_URL_PROPERTY_ID, response.getBaseUrl(), requestedIds);
-        setResourceProperty(resource, REPOSITORY_OS_TYPE_PROPERTY_ID, response.getOsType(), requestedIds);
-        setResourceProperty(resource, REPOSITORY_REPO_ID_PROPERTY_ID, response.getRepoId(), requestedIds);
-        setResourceProperty(resource, REPOSITORY_MIRRORS_LIST_PROPERTY_ID, response.getMirrorsList(), requestedIds);
-        setResourceProperty(resource, REPOSITORY_DEFAULT_BASE_URL_PROPERTY_ID, response.getDefaultBaseUrl(), requestedIds);
-        setResourceProperty(resource, REPOSITORY_UNIQUE_PROPERTY_ID, response.isUnique(), requestedIds);
-        setResourceProperty(resource, REPOSITORY_TAGS_PROPERTY_ID, response.getTags(), requestedIds);
-        setResourceProperty(resource, REPOSITORY_APPLICABLE_SERVICES_PROPERTY_ID, response.getApplicableServices(), requestedIds);
-        if (null != response.getClusterVersionId()) {
-          setResourceProperty(resource, REPOSITORY_CLUSTER_STACK_VERSION_PROPERTY_ID, response.getClusterVersionId(), requestedIds);
-        }
+      Resource resource = new ResourceImpl(Resource.Type.Repository);
+
+      setResourceProperty(resource, REPOSITORY_STACK_NAME_PROPERTY_ID, response.getStackName(), requestedIds);
+      setResourceProperty(resource, REPOSITORY_STACK_VERSION_PROPERTY_ID, response.getStackVersion(), requestedIds);
+      setResourceProperty(resource, REPOSITORY_REPO_NAME_PROPERTY_ID, response.getRepoName(), requestedIds);
+      setResourceProperty(resource, REPOSITORY_DISTRIBUTION_PROPERTY_ID, response.getDistribution(), requestedIds);
+      setResourceProperty(resource, REPOSITORY_COMPONENTS_PROPERTY_ID, response.getComponents(), requestedIds);
+      setResourceProperty(resource, REPOSITORY_BASE_URL_PROPERTY_ID, URLCredentialsHider.hideCredentials(response.getBaseUrl()), requestedIds);
+      setResourceProperty(resource, REPOSITORY_OS_TYPE_PROPERTY_ID, response.getOsType(), requestedIds);
+      setResourceProperty(resource, REPOSITORY_REPO_ID_PROPERTY_ID, response.getRepoId(), requestedIds);
+      setResourceProperty(resource, REPOSITORY_MIRRORS_LIST_PROPERTY_ID, response.getMirrorsList(), requestedIds);
+      setResourceProperty(resource, REPOSITORY_DEFAULT_BASE_URL_PROPERTY_ID, URLCredentialsHider.hideCredentials(response.getDefaultBaseUrl()), requestedIds);
+      setResourceProperty(resource, REPOSITORY_UNIQUE_PROPERTY_ID, response.isUnique(), requestedIds);
+      setResourceProperty(resource, REPOSITORY_TAGS_PROPERTY_ID, response.getTags(), requestedIds);
+      setResourceProperty(resource, REPOSITORY_APPLICABLE_SERVICES_PROPERTY_ID, response.getApplicableServices(), requestedIds);
+      if (null != response.getClusterVersionId()) {
+        setResourceProperty(resource, REPOSITORY_CLUSTER_STACK_VERSION_PROPERTY_ID, response.getClusterVersionId(), requestedIds);
+      }
 
-        if (null != response.getRepositoryVersionId()) {
-          setResourceProperty(resource, REPOSITORY_REPOSITORY_VERSION_ID_PROPERTY_ID, response.getRepositoryVersionId(), requestedIds);
-        }
+      if (null != response.getRepositoryVersionId()) {
+        setResourceProperty(resource, REPOSITORY_REPOSITORY_VERSION_ID_PROPERTY_ID, response.getRepositoryVersionId(), requestedIds);
+      }
 
-        if (null != response.getVersionDefinitionId()) {
-          setResourceProperty(resource, REPOSITORY_VERSION_DEFINITION_ID_PROPERTY_ID,
-              response.getVersionDefinitionId(), requestedIds);
-        }
+      if (null != response.getVersionDefinitionId()) {
+        setResourceProperty(resource, REPOSITORY_VERSION_DEFINITION_ID_PROPERTY_ID,
+            response.getVersionDefinitionId(), requestedIds);
+      }
 
-        resources.add(resource);
+      resources.add(resource);
     }
 
     return resources;
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProvider.java
index 4645da4801..9fcda17944 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryVersionResourceProvider.java
@@ -65,6 +65,7 @@ import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.repository.ManifestServiceInfo;
 import org.apache.ambari.server.state.repository.VersionDefinitionXml;
+import org.apache.ambari.server.utils.URLCredentialsHider;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang.ObjectUtils;
 import org.apache.commons.lang.StringUtils;
@@ -480,7 +481,8 @@ public class RepositoryVersionResourceProvider extends AbstractAuthorizedResourc
       for (RepoDefinitionEntity repositoryEntity : os.getRepoDefinitionEntities()) {
         String baseUrl = repositoryEntity.getBaseUrl();
         if (!skipUrlCheck && os.isAmbariManaged() && existingRepoUrls.contains(baseUrl)) {
-          throw new DuplicateResourceException("Base url " + baseUrl + " is already defined for another repository version. " +
+          throw new DuplicateResourceException("Base url " + URLCredentialsHider.hideCredentials(baseUrl) +
+                  " is already defined for another repository version. " +
                   "Setting up base urls that contain the same versions of components will cause stack upgrade to fail.");
         }
       }
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/URLStreamProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/URLStreamProvider.java
index 765b93e519..ab3189b459 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/URLStreamProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/URLStreamProvider.java
@@ -38,7 +38,9 @@ import javax.net.ssl.TrustManagerFactory;
 import org.apache.ambari.server.configuration.ComponentSSLConfiguration;
 import org.apache.ambari.server.controller.utilities.StreamProvider;
 import org.apache.ambari.server.proxy.ProxyService;
+import org.apache.ambari.server.utils.URLCredentialsHider;
 import org.apache.ambari.spi.net.HttpURLConnectionProvider;
+import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.io.IOUtils;
 import org.apache.http.HttpStatus;
 import org.slf4j.Logger;
@@ -52,6 +54,8 @@ public class URLStreamProvider implements StreamProvider {
   public static final String COOKIE = "Cookie";
   private static final String WWW_AUTHENTICATE = "WWW-Authenticate";
   private static final String NEGOTIATE = "Negotiate";
+  private static final String AUTHORIZATION = "Authorization";
+  private static final String BASIC_AUTH = "Basic %s";
   private static final Logger LOG = LoggerFactory.getLogger(URLStreamProvider.class);
 
   private boolean setupTruststoreForHttps;
@@ -177,17 +181,18 @@ public class URLStreamProvider implements StreamProvider {
   public HttpURLConnection processURL(String spec, String requestMethod, byte[] body, Map<String, List<String>> headers)
           throws IOException {
     if (LOG.isDebugEnabled()) {
-      LOG.debug("readFrom spec:{}", spec);
+      LOG.debug("readFrom spec:{}", URLCredentialsHider.hideCredentials(spec));
     }
 
+    URL url = new URL(spec);
     HttpURLConnection connection = (spec.startsWith("https") && setupTruststoreForHttps) ?
-            getSSLConnection(spec) : getConnection(spec);
+            getSSLConnection(spec) : getConnection(url);
 
     AppCookieManager appCookieManager = getAppCookieManager();
 
     String appCookie = appCookieManager.getCachedAppCookie(spec);
     if (appCookie != null) {
-      LOG.debug("Using cached app cookie for URL:{}", spec);
+      LOG.debug("Using cached app cookie for URL:{}", URLCredentialsHider.hideCredentials(spec));
 
       // allow for additional passed in cookies
       if (headers == null || headers.isEmpty()) {
@@ -217,16 +222,21 @@ public class URLStreamProvider implements StreamProvider {
       connection.getOutputStream().write(body);
     }
 
+    if (url.getUserInfo() != null) {
+      String basicAuth = String.format(BASIC_AUTH, new String(new Base64().encode(url.getUserInfo().getBytes())));
+      connection.setRequestProperty(AUTHORIZATION, basicAuth);
+    }
+
     int statusCode = connection.getResponseCode();
     if (statusCode == HttpStatus.SC_UNAUTHORIZED ) {
       String wwwAuthHeader = connection.getHeaderField(WWW_AUTHENTICATE);
       if (LOG.isInfoEnabled()) {
-        LOG.info("Received WWW-Authentication header:" + wwwAuthHeader + ", for URL:" + spec);
+        LOG.info("Received WWW-Authentication header:" + wwwAuthHeader + ", for URL:" +
+                URLCredentialsHider.hideCredentials(spec));
       }
       if (wwwAuthHeader != null &&
         wwwAuthHeader.trim().startsWith(NEGOTIATE)) {
-        connection = spec.startsWith("https") ?
-           getSSLConnection(spec) : getConnection(spec);
+        connection = spec.startsWith("https") ? getSSLConnection(spec) : getConnection(url);
         appCookie = appCookieManager.getAppCookie(spec, true);
         connection.setRequestProperty(COOKIE, appCookie);
         connection.setConnectTimeout(connTimeout);
@@ -237,14 +247,16 @@ public class URLStreamProvider implements StreamProvider {
       } else {
         // no supported authentication type found
         // we would let the original response propagate
-        LOG.error("Unsupported WWW-Authentication header:" + wwwAuthHeader+ ", for URL:" + spec);
+        LOG.error("Unsupported WWW-Authentication header:" + wwwAuthHeader+ ", for URL:" +
+                URLCredentialsHider.hideCredentials(spec));
         return connection;
       }
     } else {
         // not a 401 Unauthorized status code
         // we would let the original response propagate
         if (statusCode == HttpStatus.SC_NOT_FOUND || statusCode == HttpStatus.SC_FORBIDDEN){
-          LOG.error(String.format("Received HTTP %s response from URL: %s", statusCode, spec));
+          LOG.error(String.format("Received HTTP %s response from URL: %s", statusCode,
+                  URLCredentialsHider.hideCredentials(spec)));
         }
         return connection;
     }
@@ -281,8 +293,8 @@ public class URLStreamProvider implements StreamProvider {
   // ----- helper methods ----------------------------------------------------
 
   // Get a connection
-  protected HttpURLConnection getConnection(String spec) throws IOException {
-    return (HttpURLConnection) new URL(spec).openConnection();
+  protected HttpURLConnection getConnection(URL url) throws IOException {
+    return (HttpURLConnection) url.openConnection();
   }
 
   // Get an ssl connection
@@ -294,7 +306,8 @@ public class URLStreamProvider implements StreamProvider {
 
           if (trustStorePath == null || trustStorePassword == null) {
             String msg =
-                String.format("Can't get secure connection to %s.  Truststore path or password is not set.", spec);
+                    String.format("Can't get secure connection to %s.  Truststore path or password is not set.",
+                            URLCredentialsHider.hideCredentials(spec));
 
             LOG.error(msg);
             throw new IllegalStateException(msg);
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/upgrade/RepositoryVersionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/upgrade/RepositoryVersionHelper.java
index 204f82f397..dc9137505f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/stack/upgrade/RepositoryVersionHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/upgrade/RepositoryVersionHelper.java
@@ -489,57 +489,6 @@ public class RepositoryVersionHelper {
     }
   }
 
-
-  /**
-   * Get repository info given a cluster and host.
-   *
-   * @param cluster  the cluster
-   * @param host     the host
-   *
-   * @return the repo info
-   *
-   * @deprecated use {@link #getCommandRepository(Cluster, ServiceComponent, Host)} instead.
-   * @throws SystemException if the repository information can not be obtained
-   */
-  @Deprecated
-  public String getRepoInfo(Cluster cluster, ServiceComponent component, Host host) throws SystemException {
-    final JsonArray jsonList = getBaseUrls(cluster, component, host);
-    final RepositoryVersionEntity rve = getRepositoryVersionEntity(cluster, component);
-
-    if (null == rve || null == jsonList) {
-      return "";
-    }
-
-    final JsonArray result = new JsonArray();
-
-    for (JsonElement e : jsonList) {
-      JsonObject obj = e.getAsJsonObject();
-
-      String repoId = obj.has("repoId") ? obj.get("repoId").getAsString() : null;
-      String repoName = obj.has("repoName") ? obj.get("repoName").getAsString() : null;
-      String baseUrl = obj.has("baseUrl") ? obj.get("baseUrl").getAsString() : null;
-      String osType = obj.has("osType") ? obj.get("osType").getAsString() : null;
-
-      if (null == repoId || null == baseUrl || null == osType || null == repoName) {
-        continue;
-      }
-
-      for (RepoOsEntity ose : rve.getRepoOsEntities()) {
-        if (ose.getFamily().equals(osType) && ose.isAmbariManaged()) {
-          for (RepoDefinitionEntity re : ose.getRepoDefinitionEntities()) {
-            if (re.getRepoName().equals(repoName) &&
-              !re.getBaseUrl().equals(baseUrl)) {
-              obj.addProperty("baseUrl", re.getBaseUrl());
-            }
-          }
-          result.add(e);
-        }
-      }
-    }
-    return result.toString();
-  }
-
-
   /**
    * Executed by two different representations of repos.  When we are comfortable with the new
    * implementation, this may be removed and called inline in {@link #getCommandRepository(Cluster, ServiceComponent, Host)}
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java
index ba07105db6..98d42ca659 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/RepositoryInfo.java
@@ -27,6 +27,7 @@ import org.apache.ambari.annotations.Experimental;
 import org.apache.ambari.annotations.ExperimentalFeature;
 import org.apache.ambari.server.controller.RepositoryResponse;
 import org.apache.ambari.server.state.stack.RepoTag;
+import org.apache.ambari.server.utils.URLCredentialsHider;
 import org.apache.commons.lang.StringUtils;
 
 import com.google.common.base.Function;
@@ -196,7 +197,7 @@ public class RepositoryInfo {
     return "[ repoInfo: "
         + ", osType=" + osType
         + ", repoId=" + repoId
-        + ", baseUrl=" + baseUrl
+        + ", baseUrl=" + URLCredentialsHider.hideCredentials(baseUrl)
         + ", repoName=" + repoName
         + ", distribution=" + distribution
         + ", components=" + components
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/utils/URLCredentialsHider.java b/ambari-server/src/main/java/org/apache/ambari/server/utils/URLCredentialsHider.java
new file mode 100644
index 0000000000..bb3a79a7b1
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/utils/URLCredentialsHider.java
@@ -0,0 +1,55 @@
+/*
+ * 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.ambari.server.utils;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Provides functionality for hiding credentials in URLs.
+ */
+public class URLCredentialsHider {
+  public static final String INVALID_URL = "invalid_url";
+  public static final String HIDDEN_USER = "****";
+  public static final String HIDDEN_CREDENTIALS = HIDDEN_USER + ":" + HIDDEN_USER;
+
+  public static String hideCredentials(String urlString) {
+    if (StringUtils.isEmpty(urlString)) {
+      return urlString;
+    }
+    URL url;
+    try {
+      url = new URL(urlString);
+    } catch (MalformedURLException e) {
+      // it is better to miss url instead of spreading it out
+      return INVALID_URL;
+    }
+    String userInfo = url.getUserInfo();
+    if (StringUtils.isNotEmpty(userInfo)) {
+      if (userInfo.contains(":")) {
+        return urlString.replaceFirst(userInfo, HIDDEN_CREDENTIALS);
+      } else {
+        return urlString.replaceFirst(userInfo, HIDDEN_USER);
+      }
+    }
+    return urlString;
+  }
+}
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/URLStreamProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/URLStreamProviderTest.java
index 6013993851..c3d306a03b 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/URLStreamProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/URLStreamProviderTest.java
@@ -25,6 +25,7 @@ import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
 
 import java.net.HttpURLConnection;
+import java.net.URL;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -47,17 +48,20 @@ public class URLStreamProviderTest {
         withConstructor(Integer.TYPE, Integer.TYPE, String.class, String.class, String.class).
         withArgs(1000, 1000, "path", "password", "type").
         addMockedMethod("getAppCookieManager").
-        addMockedMethod("getConnection", String.class).
+        addMockedMethod("getConnection", URL.class).
         createMock();
 
+    String fakeURL = "http://fakehost";
+    URL url = new URL(fakeURL);
+
     expect(urlStreamProvider.getAppCookieManager()).andReturn(appCookieManager).anyTimes();
-    expect(urlStreamProvider.getConnection("spec")).andReturn(connection);
+    expect(urlStreamProvider.getConnection(url)).andReturn(connection);
 
     Map<String, List<String>> headerMap = new HashMap<>();
     headerMap.put("Header1", Collections.singletonList("value"));
     headerMap.put("Cookie", Collections.singletonList("FOO=bar"));
 
-    expect(appCookieManager.getCachedAppCookie("spec")).andReturn("APPCOOKIE=abcdef");
+    expect(appCookieManager.getCachedAppCookie(fakeURL)).andReturn("APPCOOKIE=abcdef");
 
     connection.setConnectTimeout(1000);
     connection.setReadTimeout(1000);
@@ -68,7 +72,7 @@ public class URLStreamProviderTest {
 
     replay(urlStreamProvider, connection, appCookieManager);
 
-    Assert.assertEquals(connection, urlStreamProvider.processURL("spec", "GET", (String) null, headerMap));
+    Assert.assertEquals(connection, urlStreamProvider.processURL(fakeURL, "GET", (String) null, headerMap));
 
     verify(urlStreamProvider, connection, appCookieManager);
   }
@@ -80,7 +84,6 @@ public class URLStreamProviderTest {
         withConstructor(Integer.TYPE, Integer.TYPE, String.class, String.class, String.class).
         withArgs(1000, 1000, null, null, null).
         addMockedMethod("getAppCookieManager").
-        addMockedMethod("getConnection", String.class).
         createMock();
 
     Map<String, List<String>> headerMap = new HashMap<>();
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/utils/URLCredentialsHiderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/utils/URLCredentialsHiderTest.java
new file mode 100644
index 0000000000..241a437f7c
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/utils/URLCredentialsHiderTest.java
@@ -0,0 +1,41 @@
+/*
+ * 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.ambari.server.utils;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class URLCredentialsHiderTest {
+
+  @Test
+  public void testHideUserInfo() {
+
+    String testURL1 = "http://user01:pass@host:8443/api/v1";
+    Assert.assertEquals(String.format("http://%s@host:8443/api/v1", URLCredentialsHider.HIDDEN_CREDENTIALS),
+                        URLCredentialsHider.hideCredentials(testURL1));
+
+    String testURL2 = "http://user01@host:8443/api/v1";
+    Assert.assertEquals(String.format("http://%s@host:8443/api/v1",
+                                      URLCredentialsHider.HIDDEN_USER),
+                        URLCredentialsHider.hideCredentials(testURL2));
+
+    String invalidURL = "htt://user01:pass@host:8443/api/v1";
+    Assert.assertEquals(URLCredentialsHider.INVALID_URL, URLCredentialsHider.hideCredentials(invalidURL));
+  }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@ambari.apache.org
For additional commands, e-mail: commits-help@ambari.apache.org