add readonly to beego middleware

Signed-off-by: wang yan <wangyan@vmware.com>
This commit is contained in:
wang yan 2020-02-25 03:41:16 +08:00
parent aa71fc43cf
commit b336875ebf
4 changed files with 53 additions and 13 deletions

View File

@ -15,6 +15,7 @@
package middlewares
import (
"github.com/goharbor/harbor/src/server/middleware/readonly"
"net/http"
"path"
"regexp"
@ -29,11 +30,28 @@ import (
)
var (
blobURLRe = regexp.MustCompile("^/v2/(" + reference.NameRegexp.String() + ")/blobs/" + reference.DigestRegexp.String())
match = regexp.MustCompile
numericRegexp = match(`[0-9]+`)
blobURLRe = match("^/v2/(" + reference.NameRegexp.String() + ")/blobs/" + reference.DigestRegexp.String())
// fetchBlobAPISkipper skip transaction middleware for fetch blob API
// because transaction use the ResponseBuffer for the response which will degrade the performance for fetch blob
fetchBlobAPISkipper = middleware.MethodAndPathSkipper(http.MethodGet, blobURLRe)
// readonlySkippers skip the post request when harbor sets to readonly.
readonlySkippers = []middleware.Skipper{
middleware.MethodAndPathSkipper(http.MethodPost, match("^/c/login")),
middleware.MethodAndPathSkipper(http.MethodPost, match("^/c/userExists")),
middleware.MethodAndPathSkipper(http.MethodPost, match("^/c/oidc/onboard")),
middleware.MethodAndPathSkipper(http.MethodPost, match("^/service/notifications/jobs/adminjob/"+numericRegexp.String())),
middleware.MethodAndPathSkipper(http.MethodPost, match("^/service/notifications/jobs/replication/"+numericRegexp.String())),
middleware.MethodAndPathSkipper(http.MethodPost, match("^/service/notifications/jobs/replication/task/"+numericRegexp.String())),
middleware.MethodAndPathSkipper(http.MethodPost, match("^/service/notifications/jobs/webhook/"+numericRegexp.String())),
middleware.MethodAndPathSkipper(http.MethodPost, match("^/service/notifications/jobs/retention/task/"+numericRegexp.String())),
middleware.MethodAndPathSkipper(http.MethodPost, match("^/service/notifications/jobs/schedules/"+numericRegexp.String())),
middleware.MethodAndPathSkipper(http.MethodPost, match("^/service/notifications/jobs/webhook/"+numericRegexp.String())),
}
)
// legacyAPISkipper skip middleware for legacy APIs
@ -52,6 +70,7 @@ func legacyAPISkipper(r *http.Request) bool {
func MiddleWares() []beego.MiddleWare {
return []beego.MiddleWare{
requestid.Middleware(),
readonly.Middleware(readonlySkippers...),
orm.Middleware(legacyAPISkipper),
transaction.Middleware(legacyAPISkipper, fetchBlobAPISkipper),
}

View File

@ -65,3 +65,34 @@ func Test_legacyAPISkipper(t *testing.T) {
})
}
}
func Test_readonlySkipper(t *testing.T) {
type args struct {
r *http.Request
}
tests := []struct {
name string
args args
want bool
}{
{"login", args{httptest.NewRequest(http.MethodPost, "/c/login", nil)}, true},
{"login get", args{httptest.NewRequest(http.MethodGet, "/c/login", nil)}, false},
{"onboard", args{httptest.NewRequest(http.MethodPost, "/c/oidc/onboard", nil)}, true},
{"user exist", args{httptest.NewRequest(http.MethodPost, "/c/userExists", nil)}, true},
{"user exist", args{httptest.NewRequest(http.MethodPost, "/service/notifications/jobs/adminjob/123456", nil)}, true},
{"user exist", args{httptest.NewRequest(http.MethodPost, "/service/notifications/jobs/adminjob/abcdefg", nil)}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var pass bool
for _, skipper := range readonlySkippers {
if got := skipper(tt.args.r); got == tt.want {
pass = true
}
}
if !pass {
t.Errorf("readonlySkippers() = %v, want %v", tt.args, tt.want)
}
})
}
}

View File

@ -59,6 +59,8 @@ func Middleware(skippers ...middleware.Skipper) func(http.Handler) http.Handler
func MiddlewareWithConfig(config Config, skippers ...middleware.Skipper) func(http.Handler) http.Handler {
if len(skippers) == 0 {
skippers = []middleware.Skipper{safeMethodSkipper}
} else {
skippers = append(skippers, []middleware.Skipper{safeMethodSkipper}...)
}
if config.ReadOnly == nil {

View File

@ -21,7 +21,6 @@ import (
"github.com/goharbor/harbor/src/server/middleware/blob"
"github.com/goharbor/harbor/src/server/middleware/contenttrust"
"github.com/goharbor/harbor/src/server/middleware/immutable"
"github.com/goharbor/harbor/src/server/middleware/readonly"
"github.com/goharbor/harbor/src/server/middleware/regtoken"
"github.com/goharbor/harbor/src/server/middleware/v2auth"
"github.com/goharbor/harbor/src/server/middleware/vulnerable"
@ -59,13 +58,11 @@ func RegisterRoutes() {
root.NewRoute().
Method(http.MethodDelete).
Path("/*/manifests/:reference").
Middleware(readonly.Middleware()).
Middleware(immutable.MiddlewareDelete()).
HandlerFunc(deleteManifest)
root.NewRoute().
Method(http.MethodPut).
Path("/*/manifests/:reference").
Middleware(readonly.Middleware()).
Middleware(immutable.MiddlewarePush()).
Middleware(blob.PutManifestMiddleware()).
HandlerFunc(putManifest)
@ -86,15 +83,6 @@ func RegisterRoutes() {
Path("/*/blobs/uploads/:session_id").
Middleware(blob.PutBlobUploadMiddleware()).
Handler(proxy)
// blob
root.NewRoute().
Method(http.MethodPost).
Method(http.MethodPut).
Method(http.MethodPatch).
Method(http.MethodDelete).
Path("/{name:.*}/blobs/").
Middleware(readonly.Middleware()).
Handler(proxy)
// others
root.NewRoute().Path("/*").Handler(proxy)
}