-
Notifications
You must be signed in to change notification settings - Fork 4.6k
/
handler.go
73 lines (65 loc) · 2.15 KB
/
handler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package regtoken
import (
"github.com/docker/distribution/registry/auth"
"github.com/goharbor/harbor/src/common/rbac"
"github.com/goharbor/harbor/src/common/utils/log"
"github.com/goharbor/harbor/src/core/middlewares/util"
pkg_token "github.com/goharbor/harbor/src/pkg/token"
"github.com/goharbor/harbor/src/pkg/token/claims/registry"
"net/http"
"strings"
)
// regTokenHandler is responsible for decoding the registry token in the docker pull request header,
// as harbor adds customized claims action into registry auth token, the middlerware is for decode it and write it into
// request context, then for other middlerwares in chain to use it to bypass request validation.
type regTokenHandler struct {
next http.Handler
}
// New ...
func New(next http.Handler) http.Handler {
return ®TokenHandler{
next: next,
}
}
// ServeHTTP ...
func (r *regTokenHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
imgRaw := req.Context().Value(util.ImageInfoCtxKey)
if imgRaw == nil {
r.next.ServeHTTP(rw, req)
return
}
img, _ := req.Context().Value(util.ImageInfoCtxKey).(util.ImageInfo)
if img.Digest == "" {
r.next.ServeHTTP(rw, req)
return
}
parts := strings.Split(req.Header.Get("Authorization"), " ")
if len(parts) != 2 || strings.ToLower(parts[0]) != "bearer" {
r.next.ServeHTTP(rw, req)
return
}
*req = *(req.WithContext(util.NewDockerPullAuthContext(req.Context(), true)))
rawToken := parts[1]
opt := pkg_token.DefaultTokenOptions()
regTK, err := pkg_token.Parse(opt, rawToken, ®istry.Claim{})
if err != nil {
log.Errorf("failed to decode reg token: %v, the error is skipped and round the request to native registry.", err)
r.next.ServeHTTP(rw, req)
return
}
accessItems := []auth.Access{}
accessItems = append(accessItems, auth.Access{
Resource: auth.Resource{
Type: rbac.ResourceRepository.String(),
Name: img.Repository,
},
Action: rbac.ActionScannerPull.String(),
})
accessSet := regTK.Claims.(*registry.Claim).GetAccess()
for _, access := range accessItems {
if accessSet.Contains(access) {
*req = *(req.WithContext(util.NewScannerPullContext(req.Context(), true)))
}
}
r.next.ServeHTTP(rw, req)
}