Skip to content

Commit 07be3dd

Browse files
committed
Add limitation for package scope check
1 parent 7afaacf commit 07be3dd

File tree

1 file changed

+59
-1
lines changed

1 file changed

+59
-1
lines changed

routers/api/packages/api.go

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package packages
55

66
import (
7+
"fmt"
78
"net/http"
89
"regexp"
910
"strings"
@@ -63,6 +64,20 @@ func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.Context) {
6364
ctx.Error(http.StatusUnauthorized, "reqPackageAccess", "user should have specific permission or be a site admin")
6465
return
6566
}
67+
68+
// check if scope only applies to public resources
69+
publicOnly, err := scope.PublicOnly()
70+
if err != nil {
71+
ctx.Error(http.StatusForbidden, "tokenRequiresScope", "parsing public resource scope failed: "+err.Error())
72+
return
73+
}
74+
75+
if publicOnly {
76+
if ctx.Package != nil && ctx.Package.Owner.Visibility.IsPrivate() {
77+
ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public packages")
78+
return
79+
}
80+
}
6681
}
6782
}
6883

@@ -643,11 +658,54 @@ func CommonRoutes() *web.Router {
643658
})
644659
})
645660
}, reqPackageAccess(perm.AccessModeRead))
646-
}, context.UserAssignmentWeb(), context.PackageAssignment())
661+
}, context.UserAssignmentWeb(), context.PackageAssignment(), checkPackageTokenScope)
647662

648663
return r
649664
}
650665

666+
func checkPackageTokenScope(ctx *context.Context) {
667+
// Need OAuth2 token to be present.
668+
scope, scopeExists := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope)
669+
if ctx.Data["IsApiToken"] != true || !scopeExists {
670+
return
671+
}
672+
673+
// use the http method to determine the access level
674+
requiredScopeLevel := auth_model.Read
675+
if ctx.Req.Method == "POST" || ctx.Req.Method == "PUT" || ctx.Req.Method == "PATCH" || ctx.Req.Method == "DELETE" {
676+
requiredScopeLevel = auth_model.Write
677+
}
678+
679+
// get the required scope for the given access level and category
680+
requiredScopes := auth_model.GetRequiredScopes(requiredScopeLevel, auth_model.AccessTokenScopeCategoryPackage)
681+
allow, err := scope.HasScope(requiredScopes...)
682+
if err != nil {
683+
ctx.Error(http.StatusForbidden, "tokenRequiresScope", "checking scope failed: "+err.Error())
684+
return
685+
}
686+
687+
if !allow {
688+
ctx.Error(http.StatusForbidden, "tokenRequiresScope", fmt.Sprintf("token does not have at least one of required scope(s): %v", requiredScopes))
689+
return
690+
}
691+
692+
// check if scope only applies to public resources
693+
publicOnly, err := scope.PublicOnly()
694+
if err != nil {
695+
ctx.Error(http.StatusForbidden, "tokenRequiresScope", "parsing public resource scope failed: "+err.Error())
696+
return
697+
}
698+
699+
if !publicOnly {
700+
return
701+
}
702+
703+
if ctx.Package != nil && ctx.Package.Owner.Visibility.IsPrivate() {
704+
ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public packages")
705+
return
706+
}
707+
}
708+
651709
// ContainerRoutes provides endpoints that implement the OCI API to serve containers
652710
// These have to be mounted on `/v2/...` to comply with the OCI spec:
653711
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md

0 commit comments

Comments
 (0)