mirror of
https://github.com/goharbor/harbor.git
synced 2025-01-03 06:28:06 +01:00
Remove the readonly filter (#10944)
Remove the readonly filter as we have introduced readonly middleware Signed-off-by: Wenkai Yin <yinw@vmware.com>
This commit is contained in:
parent
d21318dfcf
commit
c8ca6a5ccf
@ -1,95 +0,0 @@
|
||||
// Copyright 2018 Project Harbor Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package filter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
|
||||
"github.com/astaxie/beego/context"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
)
|
||||
|
||||
const (
|
||||
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})$`
|
||||
labelURL = `^/api/repositories/((?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)+)tags/([\w][\w.-]{0,127})/labels/[0-9]+$`
|
||||
)
|
||||
|
||||
// ReadonlyFilter filters the deletion or creation (e.g. retag) of repo/tag requests and returns 503.
|
||||
func ReadonlyFilter(ctx *context.Context) {
|
||||
filter(ctx.Request, ctx.ResponseWriter)
|
||||
}
|
||||
|
||||
func filter(req *http.Request, resp http.ResponseWriter) {
|
||||
if !config.ReadOnly() {
|
||||
return
|
||||
}
|
||||
|
||||
if matchRepoTagDelete(req) || matchRetag(req) {
|
||||
resp.WriteHeader(http.StatusServiceUnavailable)
|
||||
_, err := resp.Write([]byte("The system is in read only mode. Any modification is prohibited."))
|
||||
if err != nil {
|
||||
log.Errorf("failed to write response body: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if req.Method != http.MethodDelete {
|
||||
return false
|
||||
}
|
||||
|
||||
if inWhiteList(req) {
|
||||
return false
|
||||
}
|
||||
|
||||
re := regexp.MustCompile(tagURL)
|
||||
s := re.FindStringSubmatch(req.URL.Path)
|
||||
if len(s) == 3 {
|
||||
return true
|
||||
}
|
||||
|
||||
re = regexp.MustCompile(repoURL)
|
||||
s = re.FindStringSubmatch(req.URL.Path)
|
||||
if len(s) == 2 {
|
||||
return true
|
||||
}
|
||||
|
||||
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 {
|
||||
re := regexp.MustCompile(labelURL)
|
||||
s := re.FindStringSubmatch(req.URL.Path)
|
||||
if len(s) == 3 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
// Copyright 2018 Project Harbor Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package filter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestReadonlyFilter(t *testing.T) {
|
||||
|
||||
var defaultConfig = map[string]interface{}{
|
||||
common.ReadOnly: true,
|
||||
}
|
||||
config.Upload(defaultConfig)
|
||||
|
||||
assert := assert.New(t)
|
||||
req1, _ := http.NewRequest("DELETE", "http://127.0.0.1:5000/api/repositories/library/ubuntu", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
filter(req1, rec)
|
||||
assert.Equal(http.StatusServiceUnavailable, rec.Code)
|
||||
|
||||
req2, _ := http.NewRequest("DELETE", "http://127.0.0.1:5000/api/repositories/library/hello-world", nil)
|
||||
rec = httptest.NewRecorder()
|
||||
filter(req2, rec)
|
||||
assert.Equal(http.StatusServiceUnavailable, rec.Code)
|
||||
|
||||
req3, _ := http.NewRequest("DELETE", "http://127.0.0.1:5000/api/repositories/library/hello-world/tags/14.04", nil)
|
||||
rec = httptest.NewRecorder()
|
||||
filter(req3, rec)
|
||||
assert.Equal(http.StatusServiceUnavailable, rec.Code)
|
||||
|
||||
req4, _ := http.NewRequest("DELETE", "http://127.0.0.1:5000/api/repositories/library/hello-world/tags/latest", nil)
|
||||
rec = httptest.NewRecorder()
|
||||
filter(req4, rec)
|
||||
assert.Equal(http.StatusServiceUnavailable, rec.Code)
|
||||
|
||||
req5, _ := http.NewRequest("DELETE", "http://127.0.0.1:5000/api/repositories/library/vmware/hello-world", nil)
|
||||
rec = httptest.NewRecorder()
|
||||
filter(req5, rec)
|
||||
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))
|
||||
}
|
@ -21,7 +21,6 @@ import (
|
||||
"strings"
|
||||
|
||||
beegoctx "github.com/astaxie/beego/context"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/api"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
@ -60,30 +59,6 @@ const (
|
||||
|
||||
var (
|
||||
reqCtxModifiers []ReqCtxModifier
|
||||
// basic auth request context modifier only takes effect on the patterns
|
||||
// in the slice
|
||||
basicAuthReqPatterns = []*pathMethod{
|
||||
// create project
|
||||
{
|
||||
path: "/api/projects",
|
||||
method: http.MethodPost,
|
||||
},
|
||||
// token service
|
||||
{
|
||||
path: "/service/token",
|
||||
method: http.MethodGet,
|
||||
},
|
||||
// delete repository
|
||||
{
|
||||
path: "/api/repositories/" + reference.NameRegexp.String(),
|
||||
method: http.MethodDelete,
|
||||
},
|
||||
// delete tag
|
||||
{
|
||||
path: "/api/repositories/" + reference.NameRegexp.String() + "/tags/" + reference.TagRegexp.String(),
|
||||
method: http.MethodDelete,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// Init ReqCtxMofiers list
|
||||
|
@ -229,7 +229,6 @@ func main() {
|
||||
filter.Init()
|
||||
beego.InsertFilter("/api/*", beego.BeforeStatic, filter.SessionCheck)
|
||||
beego.InsertFilter("/*", beego.BeforeRouter, filter.SecurityFilter)
|
||||
beego.InsertFilter("/*", beego.BeforeRouter, filter.ReadonlyFilter)
|
||||
|
||||
server.RegisterRoutes()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user