mirror of
https://github.com/goharbor/harbor
synced 2024-09-20 19:17:40 +00:00
Block retag requests in read-only mode (#6457)
Signed-off-by: cd1989 <chende@caicloud.io>
This commit is contained in:
parent
657ee8a150
commit
60d65a9d86
|
@ -25,11 +25,12 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
repoURL = `^/api/repositories/((?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)+)(?:[a-z0-9]+(?:[._-][a-z0-9]+)*)$`
|
repoURL = `^/api/repositories/((?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)+)(?:[a-z0-9]+(?:[._-][a-z0-9]+)*)$`
|
||||||
|
tagsURL = `^/api/repositories/((?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)+)tags$`
|
||||||
tagURL = `^/api/repositories/((?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)+)tags/([\w][\w.-]{0,127})$`
|
tagURL = `^/api/repositories/((?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)+)tags/([\w][\w.-]{0,127})$`
|
||||||
labelURL = `^/api/repositories/((?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)+)tags/([\w][\w.-]{0,127})/labels/[0-9]+$`
|
labelURL = `^/api/repositories/((?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)+)tags/([\w][\w.-]{0,127})/labels/[0-9]+$`
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadonlyFilter filters the delete repo/tag request and returns 503.
|
// ReadonlyFilter filters the deletion or creation (e.g. retag) of repo/tag requests and returns 503.
|
||||||
func ReadonlyFilter(ctx *context.Context) {
|
func ReadonlyFilter(ctx *context.Context) {
|
||||||
filter(ctx.Request, ctx.ResponseWriter)
|
filter(ctx.Request, ctx.ResponseWriter)
|
||||||
}
|
}
|
||||||
|
@ -38,10 +39,8 @@ func filter(req *http.Request, resp http.ResponseWriter) {
|
||||||
if !config.ReadOnly() {
|
if !config.ReadOnly() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if req.Method != http.MethodDelete {
|
|
||||||
return
|
if matchRepoTagDelete(req) || matchRetag(req) {
|
||||||
}
|
|
||||||
if matchRepoTagDelete(req) {
|
|
||||||
resp.WriteHeader(http.StatusServiceUnavailable)
|
resp.WriteHeader(http.StatusServiceUnavailable)
|
||||||
_, err := resp.Write([]byte("The system is in read only mode. Any modification is prohibited."))
|
_, err := resp.Write([]byte("The system is in read only mode. Any modification is prohibited."))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -50,8 +49,13 @@ func filter(req *http.Request, resp http.ResponseWriter) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only block repository and tag deletion
|
// matchRepoTagDelete checks whether a request is a repository or tag deletion request,
|
||||||
|
// it should be blocked in read-only mode.
|
||||||
func matchRepoTagDelete(req *http.Request) bool {
|
func matchRepoTagDelete(req *http.Request) bool {
|
||||||
|
if req.Method != http.MethodDelete {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if inWhiteList(req) {
|
if inWhiteList(req) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -71,6 +75,16 @@ func matchRepoTagDelete(req *http.Request) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// matchRetag checks whether a request is a retag request, it should be blocked in read-only mode.
|
||||||
|
func matchRetag(req *http.Request) bool {
|
||||||
|
if req.Method != http.MethodPost {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
re := regexp.MustCompile(tagsURL)
|
||||||
|
return re.MatchString(req.URL.Path)
|
||||||
|
}
|
||||||
|
|
||||||
func inWhiteList(req *http.Request) bool {
|
func inWhiteList(req *http.Request) bool {
|
||||||
re := regexp.MustCompile(labelURL)
|
re := regexp.MustCompile(labelURL)
|
||||||
s := re.FindStringSubmatch(req.URL.Path)
|
s := re.FindStringSubmatch(req.URL.Path)
|
||||||
|
|
|
@ -79,4 +79,22 @@ func TestReadonlyFilter(t *testing.T) {
|
||||||
filter(req5, rec)
|
filter(req5, rec)
|
||||||
assert.Equal(http.StatusServiceUnavailable, rec.Code)
|
assert.Equal(http.StatusServiceUnavailable, rec.Code)
|
||||||
|
|
||||||
|
req6, _ := http.NewRequest("POST", "http://127.0.0.1:5000/api/repositories/library/hello-world/tags", nil)
|
||||||
|
rec = httptest.NewRecorder()
|
||||||
|
filter(req6, rec)
|
||||||
|
assert.Equal(http.StatusServiceUnavailable, rec.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMatchRetag(t *testing.T) {
|
||||||
|
req1, _ := http.NewRequest("POST", "http://127.0.0.1:5000/api/repositories/library/hello-world/tags", nil)
|
||||||
|
assert.True(t, matchRetag(req1))
|
||||||
|
|
||||||
|
req2, _ := http.NewRequest("POST", "http://127.0.0.1:5000/api/repositories/library/hello-world/tags/v1.0", nil)
|
||||||
|
assert.False(t, matchRetag(req2))
|
||||||
|
|
||||||
|
req3, _ := http.NewRequest("GET", "http://127.0.0.1:5000/api/repositories/library/hello-world/tags", nil)
|
||||||
|
assert.False(t, matchRetag(req3))
|
||||||
|
|
||||||
|
req4, _ := http.NewRequest("POST", "http://127.0.0.1:5000/api/repositories/library/hello-world", nil)
|
||||||
|
assert.False(t, matchRetag(req4))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user