mirror of
https://github.com/goharbor/harbor.git
synced 2025-02-01 20:41:22 +01:00
Fix bug in ping registry API
Fix bug in ping registry API: accept both ID and other properties Signed-off-by: Wenkai Yin <yinw@vmware.com>
This commit is contained in:
parent
68342c68bc
commit
a2fcb41b31
@ -3840,6 +3840,30 @@ definitions:
|
||||
update_time:
|
||||
type: string
|
||||
description: The update time of the policy.
|
||||
PingRegistry:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
description: The ID of the registry
|
||||
type:
|
||||
type: string
|
||||
description: Type of the registry, e.g. 'harbor'.
|
||||
url:
|
||||
type: string
|
||||
description: The registry address URL string.
|
||||
credential_type:
|
||||
type: string
|
||||
description: Credential type of the registry, e.g. 'basic'.
|
||||
access_key:
|
||||
type: string
|
||||
description: The registry access key.
|
||||
access_secret:
|
||||
type: string
|
||||
description: The registry access secret.
|
||||
insecure:
|
||||
type: boolean
|
||||
description: Whether or not the certificate will be verified when Harbor tries to access the server.
|
||||
PutRegistry:
|
||||
type: object
|
||||
properties:
|
||||
|
@ -1176,7 +1176,17 @@ func (a testapi) RegistryCreate(authInfo usrInfo, registry *model.Registry) (int
|
||||
return code, err
|
||||
}
|
||||
|
||||
func (a testapi) RegistryPing(authInfo usrInfo, registry *model.Registry) (int, error) {
|
||||
type pingReq struct {
|
||||
ID *int64 `json:"id"`
|
||||
Type *string `json:"type"`
|
||||
URL *string `json:"url"`
|
||||
CredentialType *string `json:"credential_type"`
|
||||
AccessKey *string `json:"access_key"`
|
||||
AccessSecret *string `json:"access_secret"`
|
||||
Insecure *bool `json:"insecure"`
|
||||
}
|
||||
|
||||
func (a testapi) RegistryPing(authInfo usrInfo, registry *pingReq) (int, error) {
|
||||
_sling := sling.New().Base(a.basePath).Post("/api/registries/ping").BodyJSON(registry)
|
||||
code, _, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
return code, err
|
||||
|
@ -5,12 +5,13 @@ import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/goharbor/harbor/src/replication/ng/event"
|
||||
|
||||
common_http "github.com/goharbor/harbor/src/common/http"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/core/api/models"
|
||||
"github.com/goharbor/harbor/src/replication/ng"
|
||||
"github.com/goharbor/harbor/src/replication/ng/adapter"
|
||||
"github.com/goharbor/harbor/src/replication/ng/event"
|
||||
"github.com/goharbor/harbor/src/replication/ng/model"
|
||||
"github.com/goharbor/harbor/src/replication/ng/policy"
|
||||
"github.com/goharbor/harbor/src/replication/ng/registry"
|
||||
@ -42,38 +43,84 @@ func (t *RegistryAPI) Prepare() {
|
||||
|
||||
// Ping checks health status of a registry
|
||||
func (t *RegistryAPI) Ping() {
|
||||
r := &model.Registry{}
|
||||
t.DecodeJSONReqAndValidate(r)
|
||||
req := struct {
|
||||
ID *int64 `json:"id"`
|
||||
Type *string `json:"type"`
|
||||
URL *string `json:"url"`
|
||||
CredentialType *string `json:"credential_type"`
|
||||
AccessKey *string `json:"access_key"`
|
||||
AccessSecret *string `json:"access_secret"`
|
||||
Insecure *bool `json:"insecure"`
|
||||
}{}
|
||||
t.DecodeJSONReq(&req)
|
||||
|
||||
reg := &model.Registry{}
|
||||
var err error
|
||||
id := r.ID
|
||||
if id != 0 {
|
||||
r, err = t.manager.Get(id)
|
||||
if req.ID != nil {
|
||||
reg, err = t.manager.Get(*req.ID)
|
||||
if err != nil {
|
||||
log.Errorf("failed to get registry %s: %v", r.Name, err)
|
||||
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
||||
t.HandleInternalServerError(fmt.Sprintf("failed to get registry %d: %v", *req.ID, err))
|
||||
return
|
||||
}
|
||||
|
||||
if r == nil {
|
||||
t.CustomAbort(http.StatusNotFound, fmt.Sprintf("Registry %d not found", id))
|
||||
if reg == nil {
|
||||
t.HandleNotFound(fmt.Sprintf("registry %d not found", *req.ID))
|
||||
return
|
||||
}
|
||||
}
|
||||
if req.Type != nil {
|
||||
reg.Type = model.RegistryType(*req.Type)
|
||||
}
|
||||
if req.URL != nil {
|
||||
url, err := utils.ParseEndpoint(*req.URL)
|
||||
if err != nil {
|
||||
t.HandleBadRequest(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(r.URL) == 0 {
|
||||
t.CustomAbort(http.StatusBadRequest, "URL can't be emptry")
|
||||
// Prevent SSRF security issue #3755
|
||||
reg.URL = url.Scheme + "://" + url.Host + url.Path
|
||||
}
|
||||
if req.CredentialType != nil {
|
||||
if reg.Credential == nil {
|
||||
reg.Credential = &model.Credential{}
|
||||
}
|
||||
reg.Credential.Type = model.CredentialType(*req.CredentialType)
|
||||
}
|
||||
if req.AccessKey != nil {
|
||||
if reg.Credential == nil {
|
||||
reg.Credential = &model.Credential{}
|
||||
}
|
||||
reg.Credential.AccessKey = *req.AccessKey
|
||||
}
|
||||
if req.AccessSecret != nil {
|
||||
if reg.Credential == nil {
|
||||
reg.Credential = &model.Credential{}
|
||||
}
|
||||
reg.Credential.AccessSecret = *req.AccessSecret
|
||||
}
|
||||
if req.Insecure != nil {
|
||||
reg.Insecure = *req.Insecure
|
||||
}
|
||||
if len(reg.Type) == 0 || len(reg.URL) == 0 {
|
||||
t.HandleBadRequest("type or url cannot be empty")
|
||||
return
|
||||
}
|
||||
|
||||
status, err := registry.CheckHealthStatus(r)
|
||||
status, err := registry.CheckHealthStatus(reg)
|
||||
if err != nil {
|
||||
t.CustomAbort(http.StatusInternalServerError, fmt.Sprintf("Ping registry %s error: %v", r.URL, err))
|
||||
e, ok := err.(*common_http.Error)
|
||||
if ok && e.Code == http.StatusUnauthorized {
|
||||
t.HandleBadRequest("invalid credential")
|
||||
return
|
||||
}
|
||||
t.HandleInternalServerError(fmt.Sprintf("failed to check health of registry %s: %v", reg.URL, err))
|
||||
return
|
||||
}
|
||||
|
||||
if status != model.Healthy {
|
||||
t.CustomAbort(http.StatusBadRequest, fmt.Sprintf("Ping registry %d failed", r.ID))
|
||||
t.HandleBadRequest("")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
var (
|
||||
testRegistry = &model.Registry{
|
||||
Name: "test1",
|
||||
URL: "https://test.harbor.io",
|
||||
URL: "https://127.0.0.1",
|
||||
Type: "harbor",
|
||||
Credential: &model.Credential{
|
||||
Type: model.CredentialTypeBasic,
|
||||
@ -120,35 +120,20 @@ func (suite *RegistrySuite) TestPost() {
|
||||
func (suite *RegistrySuite) TestPing() {
|
||||
assert := assert.New(suite.T())
|
||||
|
||||
code, err := suite.testAPI.RegistryPing(*admin, &model.Registry{
|
||||
ID: suite.defaultRegistry.ID,
|
||||
})
|
||||
assert.Nil(err)
|
||||
assert.Equal(http.StatusInternalServerError, code)
|
||||
|
||||
code, err = suite.testAPI.RegistryPing(*admin, &model.Registry{
|
||||
ID: -1,
|
||||
})
|
||||
var id int64 = -1
|
||||
code, err := suite.testAPI.RegistryPing(*admin,
|
||||
&pingReq{
|
||||
ID: &id,
|
||||
})
|
||||
assert.Nil(err)
|
||||
assert.Equal(http.StatusNotFound, code)
|
||||
|
||||
code, err = suite.testAPI.RegistryPing(*admin, &model.Registry{})
|
||||
code, err = suite.testAPI.RegistryPing(*admin, nil)
|
||||
assert.Nil(err)
|
||||
assert.Equal(http.StatusBadRequest, code)
|
||||
|
||||
code, err = suite.testAPI.RegistryPing(*admin, &model.Registry{
|
||||
URL: "http://foo.bar",
|
||||
Credential: &model.Credential{
|
||||
Type: model.CredentialTypeBasic,
|
||||
AccessKey: "admin",
|
||||
AccessSecret: "Harbor12345",
|
||||
},
|
||||
})
|
||||
assert.Nil(err)
|
||||
assert.NotEqual(http.StatusBadRequest, code)
|
||||
|
||||
code, err = suite.testAPI.RegistryPing(*testUser, &model.Registry{
|
||||
ID: suite.defaultRegistry.ID,
|
||||
code, err = suite.testAPI.RegistryPing(*testUser, &pingReq{
|
||||
ID: &suite.defaultRegistry.ID,
|
||||
})
|
||||
assert.Nil(err)
|
||||
assert.Equal(http.StatusForbidden, code)
|
||||
|
Loading…
Reference in New Issue
Block a user