summaryrefslogtreecommitdiffstats
path: root/routers
diff options
context:
space:
mode:
authorJohn Olheiser <john.olheiser@gmail.com>2023-04-26 19:24:03 -0500
committerGitHub <noreply@github.com>2023-04-26 19:24:03 -0500
commit5e360241053f6fcfb7f8b89373cba431adaf44ce (patch)
tree8253e76b296a437b3e288e5cc0b70070e9578946 /routers
parent8f57aa014b5642bcd33a6b22492df3c63f03d808 (diff)
downloadgitea-5e360241053f6fcfb7f8b89373cba431adaf44ce.tar.gz
gitea-5e360241053f6fcfb7f8b89373cba431adaf44ce.zip
Require repo scope for PATs for private repos and basic authentication (#24362)
> The scoped token PR just checked all API routes but in fact, some web routes like `LFS`, git `HTTP`, container, and attachments supports basic auth. This PR added scoped token check for them. --------- Signed-off-by: jolheiser <john.olheiser@gmail.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Diffstat (limited to 'routers')
-rw-r--r--routers/api/packages/api.go27
-rw-r--r--routers/web/repo/attachment.go5
-rw-r--r--routers/web/repo/http.go11
3 files changed, 40 insertions, 3 deletions
diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go
index 8bf5dbab35..d5acd3d261 100644
--- a/routers/api/packages/api.go
+++ b/routers/api/packages/api.go
@@ -9,6 +9,7 @@ import (
"regexp"
"strings"
+ auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
@@ -36,6 +37,32 @@ import (
func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.Context) {
return func(ctx *context.Context) {
+ if ctx.Data["IsApiToken"] == true {
+ scope, ok := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope)
+ if ok { // it's a personal access token but not oauth2 token
+ scopeMatched := false
+ var err error
+ if accessMode == perm.AccessModeRead {
+ scopeMatched, err = scope.HasScope(auth_model.AccessTokenScopeReadPackage)
+ if err != nil {
+ ctx.Error(http.StatusInternalServerError, "HasScope", err.Error())
+ return
+ }
+ } else if accessMode == perm.AccessModeWrite {
+ scopeMatched, err = scope.HasScope(auth_model.AccessTokenScopeWritePackage)
+ if err != nil {
+ ctx.Error(http.StatusInternalServerError, "HasScope", err.Error())
+ return
+ }
+ }
+ if !scopeMatched {
+ ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="Gitea Package API"`)
+ ctx.Error(http.StatusUnauthorized, "reqPackageAccess", "user should have specific permission or be a site admin")
+ return
+ }
+ }
+ }
+
if ctx.Package.AccessMode < accessMode && !ctx.IsUserSiteAdmin() {
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="Gitea Package API"`)
ctx.Error(http.StatusUnauthorized, "reqPackageAccess", "user should have specific permission or be a site admin")
diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go
index 9fb9cb00bf..c6ea4e3cdb 100644
--- a/routers/web/repo/attachment.go
+++ b/routers/web/repo/attachment.go
@@ -110,6 +110,11 @@ func ServeAttachment(ctx *context.Context, uuid string) {
return
}
} else { // If we have the repository we check access
+ context.CheckRepoScopedToken(ctx, repository)
+ if ctx.Written() {
+ return
+ }
+
perm, err := access_model.GetUserRepoPermission(ctx, repository, ctx.Doer)
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err.Error())
diff --git a/routers/web/repo/http.go b/routers/web/repo/http.go
index a01bb4f28e..4e45a9b6e2 100644
--- a/routers/web/repo/http.go
+++ b/routers/web/repo/http.go
@@ -19,7 +19,7 @@ import (
"time"
actions_model "code.gitea.io/gitea/models/actions"
- "code.gitea.io/gitea/models/auth"
+ auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
@@ -152,13 +152,18 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
return
}
+ context.CheckRepoScopedToken(ctx, repo)
+ if ctx.Written() {
+ return
+ }
+
if ctx.IsBasicAuth && ctx.Data["IsApiToken"] != true && ctx.Data["IsActionsToken"] != true {
- _, err = auth.GetTwoFactorByUID(ctx.Doer.ID)
+ _, err = auth_model.GetTwoFactorByUID(ctx.Doer.ID)
if err == nil {
// TODO: This response should be changed to "invalid credentials" for security reasons once the expectation behind it (creating an app token to authenticate) is properly documented
ctx.PlainText(http.StatusUnauthorized, "Users with two-factor authentication enabled cannot perform HTTP/HTTPS operations via plain username and password. Please create and use a personal access token on the user settings page")
return
- } else if !auth.IsErrTwoFactorNotEnrolled(err) {
+ } else if !auth_model.IsErrTwoFactorNotEnrolled(err) {
ctx.ServerError("IsErrTwoFactorNotEnrolled", err)
return
}