mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-17 15:55:26 +01:00
Merge pull request #7666 from wy65701436/block-multiple-mf
add multiple manifest intercepetor handler
This commit is contained in:
commit
7469204ad6
@ -79,6 +79,53 @@ func TestMatchPullManifest(t *testing.T) {
|
||||
assert.Equal("sha256:ca4626b691f57d16ce1576231e4a2e2135554d32e13a85dcff380d51fdd13f6a", tag7)
|
||||
}
|
||||
|
||||
func TestMatchPushManifest(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
req1, _ := http.NewRequest("POST", "http://127.0.0.1:5000/v2/library/ubuntu/manifests/14.04", nil)
|
||||
res1, _, _ := MatchPushManifest(req1)
|
||||
assert.False(res1, "%s %v is not a request to push manifest", req1.Method, req1.URL)
|
||||
|
||||
req2, _ := http.NewRequest("PUT", "http://192.168.0.3:80/v2/library/ubuntu/manifests/14.04", nil)
|
||||
res2, repo2, tag2 := MatchPushManifest(req2)
|
||||
assert.True(res2, "%s %v is a request to push manifest", req2.Method, req2.URL)
|
||||
assert.Equal("library/ubuntu", repo2)
|
||||
assert.Equal("14.04", tag2)
|
||||
|
||||
req3, _ := http.NewRequest("GET", "https://192.168.0.5:443/v1/library/ubuntu/manifests/14.04", nil)
|
||||
res3, _, _ := MatchPushManifest(req3)
|
||||
assert.False(res3, "%s %v is not a request to push manifest", req3.Method, req3.URL)
|
||||
|
||||
req4, _ := http.NewRequest("PUT", "https://192.168.0.5/v2/library/ubuntu/manifests/14.04", nil)
|
||||
res4, repo4, tag4 := MatchPushManifest(req4)
|
||||
assert.True(res4, "%s %v is a request to push manifest", req4.Method, req4.URL)
|
||||
assert.Equal("library/ubuntu", repo4)
|
||||
assert.Equal("14.04", tag4)
|
||||
|
||||
req5, _ := http.NewRequest("PUT", "https://myregistry.com/v2/path1/path2/golang/manifests/1.6.2", nil)
|
||||
res5, repo5, tag5 := MatchPushManifest(req5)
|
||||
assert.True(res5, "%s %v is a request to push manifest", req5.Method, req5.URL)
|
||||
assert.Equal("path1/path2/golang", repo5)
|
||||
assert.Equal("1.6.2", tag5)
|
||||
|
||||
req6, _ := http.NewRequest("PUT", "https://myregistry.com/v2/myproject/registry/manifests/sha256:ca4626b691f57d16ce1576231e4a2e2135554d32e13a85dcff380d51fdd13f6a", nil)
|
||||
res6, repo6, tag6 := MatchPushManifest(req6)
|
||||
assert.True(res6, "%s %v is a request to push manifest", req6.Method, req6.URL)
|
||||
assert.Equal("myproject/registry", repo6)
|
||||
assert.Equal("sha256:ca4626b691f57d16ce1576231e4a2e2135554d32e13a85dcff380d51fdd13f6a", tag6)
|
||||
|
||||
req7, _ := http.NewRequest("PUT", "https://myregistry.com/v2/myproject/manifests/sha256:ca4626b691f57d16ce1576231e4a2e2135554d32e13a85dcff380d51fdd13f6a", nil)
|
||||
res7, repo7, tag7 := MatchPushManifest(req7)
|
||||
assert.True(res7, "%s %v is a request to push manifest", req7.Method, req7.URL)
|
||||
assert.Equal("myproject", repo7)
|
||||
assert.Equal("sha256:ca4626b691f57d16ce1576231e4a2e2135554d32e13a85dcff380d51fdd13f6a", tag7)
|
||||
|
||||
req8, _ := http.NewRequest("PUT", "http://192.168.0.3:80/v2/library/ubuntu/manifests/14.04", nil)
|
||||
res8, repo8, tag8 := MatchPushManifest(req8)
|
||||
assert.True(res8, "%s %v is a request to push manifest", req8.Method, req8.URL)
|
||||
assert.Equal("library/ubuntu", repo8)
|
||||
assert.Equal("14.04", tag8)
|
||||
}
|
||||
|
||||
func TestMatchListRepos(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
req1, _ := http.NewRequest("POST", "http://127.0.0.1:5000/v2/_catalog", nil)
|
||||
|
@ -43,6 +43,18 @@ func MatchPullManifest(req *http.Request) (bool, string, string) {
|
||||
if req.Method != http.MethodGet {
|
||||
return false, "", ""
|
||||
}
|
||||
return matchManifestURL(req)
|
||||
}
|
||||
|
||||
// MatchPushManifest checks if the request looks like a request to push manifest. If it is returns the image and tag/sha256 digest as 2nd and 3rd return values
|
||||
func MatchPushManifest(req *http.Request) (bool, string, string) {
|
||||
if req.Method != http.MethodPut {
|
||||
return false, "", ""
|
||||
}
|
||||
return matchManifestURL(req)
|
||||
}
|
||||
|
||||
func matchManifestURL(req *http.Request) (bool, string, string) {
|
||||
re := regexp.MustCompile(manifestURLPattern)
|
||||
s := re.FindStringSubmatch(req.URL.Path)
|
||||
if len(s) == 3 {
|
||||
@ -168,6 +180,25 @@ func (rh readonlyHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
rh.next.ServeHTTP(rw, req)
|
||||
}
|
||||
|
||||
type multipleManifestHandler struct {
|
||||
next http.Handler
|
||||
}
|
||||
|
||||
// The handler is responsible for blocking request to upload manifest list by docker client, which is not supported so far by Harbor.
|
||||
func (mh multipleManifestHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
match, _, _ := MatchPushManifest(req)
|
||||
if match {
|
||||
contentType := req.Header.Get("Content-type")
|
||||
// application/vnd.docker.distribution.manifest.list.v2+json
|
||||
if strings.Contains(contentType, "manifest.list.v2") {
|
||||
log.Debugf("Content-type: %s is not supported, failing the response.", contentType)
|
||||
http.Error(rw, marshalError("UNSUPPORTED_MEDIA_TYPE", "Manifest.list is not supported."), http.StatusUnsupportedMediaType)
|
||||
return
|
||||
}
|
||||
}
|
||||
mh.next.ServeHTTP(rw, req)
|
||||
}
|
||||
|
||||
type listReposHandler struct {
|
||||
next http.Handler
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ func Init(urls ...string) error {
|
||||
return err
|
||||
}
|
||||
Proxy = httputil.NewSingleHostReverseProxy(targetURL)
|
||||
handlers = handlerChain{head: readonlyHandler{next: urlHandler{next: listReposHandler{next: contentTrustHandler{next: vulnerableHandler{next: Proxy}}}}}}
|
||||
handlers = handlerChain{head: readonlyHandler{next: urlHandler{next: multipleManifestHandler{next: listReposHandler{next: contentTrustHandler{next: vulnerableHandler{next: Proxy}}}}}}}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -93,20 +93,24 @@ func (n *NotificationHandler) Post() {
|
||||
}()
|
||||
|
||||
if action == "push" {
|
||||
go func() {
|
||||
exist := dao.RepositoryExists(repository)
|
||||
if exist {
|
||||
return
|
||||
}
|
||||
log.Debugf("Add repository %s into DB.", repository)
|
||||
repoRecord := models.RepoRecord{
|
||||
Name: repository,
|
||||
ProjectID: pro.ProjectID,
|
||||
}
|
||||
if err := dao.AddRepository(repoRecord); err != nil {
|
||||
log.Errorf("Error happens when adding repository: %v", err)
|
||||
}
|
||||
}()
|
||||
// discard the notification without tag.
|
||||
if tag != "" {
|
||||
go func() {
|
||||
exist := dao.RepositoryExists(repository)
|
||||
if exist {
|
||||
return
|
||||
}
|
||||
log.Debugf("Add repository %s into DB.", repository)
|
||||
repoRecord := models.RepoRecord{
|
||||
Name: repository,
|
||||
ProjectID: pro.ProjectID,
|
||||
}
|
||||
if err := dao.AddRepository(repoRecord); err != nil {
|
||||
log.Errorf("Error happens when adding repository: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if !coreutils.WaitForManifestReady(repository, tag, 5) {
|
||||
log.Errorf("Manifest for image %s:%s is not ready, skip the follow up actions.", repository, tag)
|
||||
return
|
||||
|
Loading…
Reference in New Issue
Block a user