From fe587d0cc83cda9e553791f5533ce3b4eaaf09ca Mon Sep 17 00:00:00 2001 From: Daniel Jiang Date: Mon, 27 Apr 2020 00:54:49 +0800 Subject: [PATCH] v2 auth middleware handles the ping request from internal When scanner like trivy handles the auth flow to pull image, it pings the /v2 and access the token service url in response body, by default it will be external endpoint of Harbor. There will be problem when Harbor is deployed on a single node with hairpinning not supported. This commit makes sure the address of token service in the challenge is internal url of core component when the request is from internal. Signed-off-by: Daniel Jiang --- src/server/middleware/v2auth/auth.go | 22 +++++++++++++++++++--- src/server/middleware/v2auth/auth_test.go | 5 ++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/server/middleware/v2auth/auth.go b/src/server/middleware/v2auth/auth.go index 826c29af0..31c5c2ef9 100644 --- a/src/server/middleware/v2auth/auth.go +++ b/src/server/middleware/v2auth/auth.go @@ -17,6 +17,7 @@ package v2auth import ( "fmt" "net/http" + "net/url" "strings" "sync" @@ -30,7 +31,9 @@ import ( serror "github.com/goharbor/harbor/src/server/error" ) -const authHeader = "Authorization" +const ( + authHeader = "Authorization" +) type reqChecker struct { pm promgr.ProjectManager @@ -86,9 +89,9 @@ func getChallenge(req *http.Request, accessList []access) string { return `Basic realm="harbor"` } // No auth header, treat it as CLI and redirect to token service - ep, err := config.ExtEndpoint() + ep, err := tokenSvcEndpoint(req) if err != nil { - logger.Errorf("failed to get the external endpoint, error: %v", err) + logger.Errorf("failed to get the endpoint for token service, error: %v", err) } tokenSvc := fmt.Sprintf("%s/service/token", strings.TrimSuffix(ep, "/")) scope := "" @@ -105,6 +108,19 @@ func getChallenge(req *http.Request, accessList []access) string { return challenge } +func tokenSvcEndpoint(req *http.Request) (string, error) { + logger := log.G(req.Context()) + rawCoreURL := config.InternalCoreURL() + if coreURL, err := url.Parse(rawCoreURL); err == nil { + if req.Host == coreURL.Host { + return rawCoreURL, nil + } + } else { + logger.Errorf("Failed to parse core url, error: %v, fallback to external endpoint", err) + } + return config.ExtEndpoint() +} + var ( once sync.Once checker reqChecker diff --git a/src/server/middleware/v2auth/auth_test.go b/src/server/middleware/v2auth/auth_test.go index eac06be67..a31301abb 100644 --- a/src/server/middleware/v2auth/auth_test.go +++ b/src/server/middleware/v2auth/auth_test.go @@ -92,6 +92,7 @@ func TestMain(m *testing.M) { } conf := map[string]interface{}{ common.ExtEndpoint: "https://harbor.test", + common.CoreURL: "https://harbor.core:8443", } config.InitWithSettings(conf) if rc := m.Run(); rc != 0 { @@ -238,12 +239,14 @@ func TestGetChallenge(t *testing.T) { })) req3x := req3.Clone(req3.Context()) req3x.SetBasicAuth("", "") + req3x.Host = "harbor.test" req4, _ := http.NewRequest(http.MethodGet, "https://registry.test/v2/project_1/hello-world/manifests/v1", nil) req4 = req4.WithContext(lib.WithArtifactInfo(context.Background(), lib.ArtifactInfo{ Repository: "project_1/hello-world", Reference: "v1", ProjectName: "project_1", })) + req4.Host = "harbor.core:8443" cases := []struct { request *http.Request @@ -275,7 +278,7 @@ func TestGetChallenge(t *testing.T) { }, { request: req4, - challenge: `Bearer realm="https://harbor.test/service/token",service="harbor-registry",scope="repository:project_1/hello-world:pull"`, + challenge: `Bearer realm="https://harbor.core:8443/service/token",service="harbor-registry",scope="repository:project_1/hello-world:pull"`, }, } for _, c := range cases {