diff options
author | John Olheiser <john.olheiser@gmail.com> | 2023-04-26 19:24:03 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-26 19:24:03 -0500 |
commit | 5e360241053f6fcfb7f8b89373cba431adaf44ce (patch) | |
tree | 8253e76b296a437b3e288e5cc0b70070e9578946 /routers | |
parent | 8f57aa014b5642bcd33a6b22492df3c63f03d808 (diff) | |
download | gitea-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.go | 27 | ||||
-rw-r--r-- | routers/web/repo/attachment.go | 5 | ||||
-rw-r--r-- | routers/web/repo/http.go | 11 |
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 } |