mirror of
https://github.com/project-zot/zot.git
synced 2024-12-16 21:56:37 -05:00
168d21da1e
Suppose we push two identical manifests (sharing same digest) but with different tags, then deleting by digest should throw an error otherwise we end up deleting all image tags (with gc) or dangling references (without gc) This behaviour is controlled via Authorization, added a new policy action named detectManifestsCollision which enables this behaviour Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com> Signed-off-by: Petu Eusebiu <peusebiu@cisco.com> Co-authored-by: Ramkumar Chinchani <rchincha@cisco.com>
71 lines
1.9 KiB
Go
71 lines
1.9 KiB
Go
package requestcontext
|
|
|
|
import (
|
|
"context"
|
|
|
|
glob "github.com/bmatcuk/doublestar/v4" //nolint:gci
|
|
"zotregistry.io/zot/errors"
|
|
)
|
|
|
|
type Key int
|
|
|
|
// request-local context key.
|
|
var authzCtxKey = Key(0) //nolint: gochecknoglobals
|
|
|
|
// pointer needed for use in context.WithValue.
|
|
func GetContextKey() *Key {
|
|
return &authzCtxKey
|
|
}
|
|
|
|
// AccessControlContext context passed down to http.Handlers.
|
|
type AccessControlContext struct {
|
|
// read method action
|
|
ReadGlobPatterns map[string]bool
|
|
// detectManifestCollision behaviour action
|
|
DmcGlobPatterns map[string]bool
|
|
IsAdmin bool
|
|
Username string
|
|
}
|
|
|
|
func GetAccessControlContext(ctx context.Context) (*AccessControlContext, error) {
|
|
authzCtxKey := GetContextKey()
|
|
if authCtx := ctx.Value(authzCtxKey); authCtx != nil {
|
|
acCtx, ok := authCtx.(AccessControlContext)
|
|
if !ok {
|
|
return nil, errors.ErrBadType
|
|
}
|
|
|
|
return &acCtx, nil
|
|
}
|
|
|
|
return nil, nil //nolint: nilnil
|
|
}
|
|
|
|
// returns either a user has or not rights on 'repository'.
|
|
func (acCtx *AccessControlContext) matchesRepo(globPatterns map[string]bool, repository string) bool {
|
|
var longestMatchedPattern string
|
|
|
|
// because of the longest path matching rule, we need to check all patterns from config
|
|
for pattern := range globPatterns {
|
|
matched, err := glob.Match(pattern, repository)
|
|
if err == nil {
|
|
if matched && len(pattern) > len(longestMatchedPattern) {
|
|
longestMatchedPattern = pattern
|
|
}
|
|
}
|
|
}
|
|
|
|
allowed := globPatterns[longestMatchedPattern]
|
|
|
|
return allowed
|
|
}
|
|
|
|
// returns either a user has or not read rights on 'repository'.
|
|
func (acCtx *AccessControlContext) CanReadRepo(repository string) bool {
|
|
return acCtx.matchesRepo(acCtx.ReadGlobPatterns, repository)
|
|
}
|
|
|
|
// returns either a user has or not detectManifestCollision rights on 'repository'.
|
|
func (acCtx *AccessControlContext) CanDetectManifestCollision(repository string) bool {
|
|
return acCtx.matchesRepo(acCtx.DmcGlobPatterns, repository)
|
|
}
|