From 0355b7558e86a2f8bf834f69e5d8ed4806e1e488 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christian=20K=C3=B6berl?= <derkoe@users.noreply.github.com>
Date: Fri, 1 Feb 2019 06:54:13 +0100
Subject: [PATCH] feat(docker): add support for basic auth (#3137)

---
 lib/datasource/docker/index.js | 19 +++++++++++++++++--
 test/datasource/docker.spec.js | 30 ++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/lib/datasource/docker/index.js b/lib/datasource/docker/index.js
index 5672436dc6..77877e4bfd 100644
--- a/lib/datasource/docker/index.js
+++ b/lib/datasource/docker/index.js
@@ -49,8 +49,6 @@ async function getAuthHeaders(registry, repository) {
       apiCheckResponse.headers['www-authenticate']
     );
 
-    // prettier-ignore
-    const authUrl = `${authenticateHeader.parms.realm}?service=${authenticateHeader.parms.service}&scope=repository:${repository}:pull`;
     const { host } = URL.parse(registry);
     const opts = hostRules.find({ platform: 'docker', host }, { json: true });
     if (opts.username && opts.password) {
@@ -59,6 +57,15 @@ async function getAuthHeaders(registry, repository) {
       );
       opts.headers = { Authorization: `Basic ${auth}` };
     }
+
+    if (authenticateHeader.scheme.toUpperCase() === 'BASIC') {
+      logger.debug(`Using Basic auth for docker registry ${repository}`);
+      await got(apiCheckUrl, opts);
+      return opts.headers;
+    }
+
+    // prettier-ignore
+    const authUrl = `${authenticateHeader.parms.realm}?service=${authenticateHeader.parms.service}&scope=repository:${repository}:pull`;
     logger.debug(
       `Obtaining docker registry token for ${repository} using url ${authUrl}`
     );
@@ -80,6 +87,14 @@ async function getAuthHeaders(registry, repository) {
       logger.debug({ err });
       return null;
     }
+    if (err.statusCode === 403) {
+      logger.info(
+        { registry, dockerRepository: repository },
+        'Not allowed to access docker registry'
+      );
+      logger.debug({ err });
+      return null;
+    }
     if (err.statusCode === 429 && registry.endsWith('docker.io')) {
       logger.warn({ err }, 'docker registry failure: too many requests');
       throw new Error('registry-failure');
diff --git a/test/datasource/docker.spec.js b/test/datasource/docker.spec.js
index 4399136459..05c5140cab 100644
--- a/test/datasource/docker.spec.js
+++ b/test/datasource/docker.spec.js
@@ -89,6 +89,36 @@ describe('api/docker', () => {
         'sha256:b3d6068234f3a18ebeedd2dab81e67b6a192e81192a099df4112ecfc7c3be84f'
       );
     });
+    it('supports basic authentication', async () => {
+      got.mockReturnValueOnce({
+        headers: {
+          'www-authenticate': 'Basic realm="My Private Docker Registry Server"',
+        },
+      });
+      got.mockReturnValueOnce({
+        statusCode: 200,
+      });
+      got.mockReturnValueOnce({
+        headers: { 'docker-content-digest': 'some-digest' },
+      });
+      const res = await docker.getDigest({ depName: 'some-dep' }, 'some-tag');
+      expect(got.mock.calls[1][1].headers.Authorization).toBe(
+        'Basic c29tZS11c2VybmFtZTpzb21lLXBhc3N3b3Jk'
+      );
+      expect(res).toBe('some-digest');
+    });
+    it('returns null for 403 with basic authentication', async () => {
+      got.mockReturnValueOnce({
+        headers: {
+          'www-authenticate': 'Basic realm="My Private Docker Registry Server"',
+        },
+      });
+      got.mockReturnValueOnce({
+        statusCode: 403,
+      });
+      const res = await docker.getDigest({ depName: 'some-dep' }, 'some-tag');
+      expect(res).toBeNull();
+    });
     it('continues without token, when no header is present', async () => {
       got.mockReturnValueOnce({
         headers: {
-- 
GitLab