Merge pull request #10908 from wy65701436/middleware-blocker

add delete manifest middleware
This commit is contained in:
Wang Yan 2020-03-05 12:00:43 +08:00 committed by GitHub
commit e79f4fd270
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 11 additions and 139 deletions

View File

@ -1,11 +1,8 @@
package contenttrust
import (
"github.com/goharbor/harbor/src/common/utils/log"
"github.com/goharbor/harbor/src/core/config"
"github.com/goharbor/harbor/src/core/middlewares/util"
internal_errors "github.com/goharbor/harbor/src/internal/error"
"github.com/goharbor/harbor/src/pkg/signature/notary"
"github.com/goharbor/harbor/src/pkg/signature"
serror "github.com/goharbor/harbor/src/server/error"
"github.com/goharbor/harbor/src/server/middleware"
"net/http"
@ -27,7 +24,7 @@ func Middleware() func(http.Handler) http.Handler {
rec := httptest.NewRecorder()
next.ServeHTTP(rec, req)
if rec.Result().StatusCode == http.StatusOK {
match, err := matchNotaryDigest(mf)
match, err := isArtifactSigned(req, mf)
if err != nil {
serror.SendError(rw, err)
return
@ -61,36 +58,12 @@ func validate(req *http.Request) (bool, middleware.ArtifactInfo) {
return true, af
}
func matchNotaryDigest(af middleware.ArtifactInfo) (bool, error) {
if NotaryEndpoint == "" {
NotaryEndpoint = config.InternalNotaryEndpoint()
}
targets, err := notary.GetInternalTargets(NotaryEndpoint, util.TokenUsername, af.Repository)
// isArtifactSigned use the sign manager to check the signature, it could handle pull by tag or digtest
// if pull by digest, any tag of the artifact is signed, will return true.
func isArtifactSigned(req *http.Request, art middleware.ArtifactInfo) (bool, error) {
checker, err := signature.GetManager().GetCheckerByRepo(req.Context(), art.Repository)
if err != nil {
return false, err
}
for _, t := range targets {
if af.Digest != "" {
d, err := notary.DigestFromTarget(t)
if err != nil {
return false, err
}
if af.Digest == d {
return true, nil
}
} else {
if t.Tag == af.Tag {
log.Debugf("found reference: %s in notary, try to match digest.", af.Tag)
d, err := notary.DigestFromTarget(t)
if err != nil {
return false, err
}
if af.Digest == d {
return true, nil
}
}
}
}
log.Debugf("image: %#v, not found in notary", af)
return false, nil
return checker.IsArtifactSigned(art.Digest), nil
}

View File

@ -1,61 +0,0 @@
package immutable
import (
"errors"
"fmt"
"github.com/goharbor/harbor/src/api/artifact"
"github.com/goharbor/harbor/src/api/tag"
common_util "github.com/goharbor/harbor/src/common/utils"
internal_errors "github.com/goharbor/harbor/src/internal/error"
serror "github.com/goharbor/harbor/src/server/error"
"github.com/goharbor/harbor/src/server/middleware"
"net/http"
)
// MiddlewareDelete ...
func MiddlewareDelete() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
if err := handleDelete(req); err != nil {
var e *ErrImmutable
if errors.As(err, &e) {
pkgE := internal_errors.New(e).WithCode(internal_errors.PreconditionCode)
serror.SendError(rw, pkgE)
return
}
pkgE := internal_errors.New(fmt.Errorf("error occurred when to handle request in immutable handler: %v", err)).WithCode(internal_errors.GeneralCode)
serror.SendError(rw, pkgE)
return
}
next.ServeHTTP(rw, req)
})
}
}
// handleDelete ...
func handleDelete(req *http.Request) error {
art, ok := middleware.ArtifactInfoFromContext(req.Context())
if !ok {
return errors.New("cannot get the manifest information from request context")
}
af, err := artifact.Ctl.GetByReference(req.Context(), art.Repository, art.Digest, &artifact.Option{
WithTag: true,
TagOption: &tag.Option{WithImmutableStatus: true},
})
if err != nil {
if internal_errors.IsErr(err, internal_errors.NotFoundCode) {
return nil
}
return err
}
_, repoName := common_util.ParseRepository(art.Repository)
for _, tag := range af.Tags {
if tag.Immutable {
return NewErrImmutable(repoName, tag.Name)
}
}
return nil
}

View File

@ -1,3 +0,0 @@
package immutable
// Tests are in the push_mf_test

View File

@ -12,8 +12,8 @@ import (
"net/http"
)
// MiddlewarePush ...
func MiddlewarePush() func(http.Handler) http.Handler {
// Middleware ...
func Middleware() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
if err := handlePush(req); err != nil {

View File

@ -54,37 +54,7 @@ func doPutManifestRequest(projectID int64, projectName, name, tag, dgt string, n
}
*req = *(req.WithContext(internal_orm.NewContext(context.TODO(), dao.GetOrmer())))
*req = *(req.WithContext(context.WithValue(req.Context(), middleware.ArtifactInfoKey, afInfo)))
h := MiddlewarePush()(n)
h.ServeHTTP(util.NewCustomResponseWriter(rr), req)
return rr.Code
}
func doDeleteManifestRequest(projectID int64, projectName, name, tag, dgt string, next ...http.HandlerFunc) int {
repository := fmt.Sprintf("%s/%s", projectName, name)
url := fmt.Sprintf("/v2/%s/manifests/%s", repository, tag)
req, _ := http.NewRequest("DELETE", url, nil)
afInfo := &middleware.ArtifactInfo{
ProjectName: projectName,
Repository: repository,
Tag: tag,
Digest: dgt,
}
rr := httptest.NewRecorder()
var n http.HandlerFunc
if len(next) > 0 {
n = next[0]
} else {
n = func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusCreated)
}
}
*req = *(req.WithContext(internal_orm.NewContext(context.TODO(), dao.GetOrmer())))
*req = *(req.WithContext(context.WithValue(req.Context(), middleware.ArtifactInfoKey, afInfo)))
h := MiddlewareDelete()(n)
h := Middleware()(n)
h.ServeHTTP(util.NewCustomResponseWriter(rr), req)
return rr.Code
@ -203,12 +173,6 @@ func (suite *HandlerSuite) TestPutDeleteManifestCreated() {
code2 := doPutManifestRequest(projectID, projectName, "photon", "latest", dgt)
suite.Equal(http.StatusCreated, code2)
code3 := doDeleteManifestRequest(projectID, projectName, "photon", "release-1.10", dgt)
suite.Equal(http.StatusPreconditionFailed, code3)
code4 := doDeleteManifestRequest(projectID, projectName, "photon", "latest", dgt)
suite.Equal(http.StatusPreconditionFailed, code4)
}
func TestMain(m *testing.M) {

View File

@ -58,12 +58,11 @@ func RegisterRoutes() {
root.NewRoute().
Method(http.MethodDelete).
Path("/*/manifests/:reference").
Middleware(immutable.MiddlewareDelete()).
HandlerFunc(deleteManifest)
root.NewRoute().
Method(http.MethodPut).
Path("/*/manifests/:reference").
Middleware(immutable.MiddlewarePush()).
Middleware(immutable.Middleware()).
Middleware(blob.PutManifestMiddleware()).
HandlerFunc(putManifest)
// initiate blob upload