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 <jiangd@vmware.com>
This commit is contained in:
Daniel Jiang 2020-04-27 00:54:49 +08:00
parent 97a7a6dc35
commit fe587d0cc8
2 changed files with 23 additions and 4 deletions

View File

@ -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

View File

@ -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 {