diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index 383fc9617f2..b4da77a6c46 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -40,9 +40,9 @@ 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 + scope, hasApiTokenScope := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) + if hasApiTokenScope { + { // request authenticated by a scoped token; enforce package scope restrictions scopeMatched := false var err error switch accessMode { diff --git a/routers/api/packages/auth.go b/routers/api/packages/auth.go index 27b761fc054..ac239021669 100644 --- a/routers/api/packages/auth.go +++ b/routers/api/packages/auth.go @@ -52,7 +52,6 @@ func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataS } if packageMeta.Scope != "" { - store.GetData()["IsApiToken"] = true store.GetData()["ApiTokenScope"] = packageMeta.Scope } diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index e138528266f..1dee830b491 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -330,7 +330,7 @@ func tokenRequiresScopes(requiredScopeCategories ...auth_model.AccessTokenScopeC // Need OAuth2 token to be present. scope, scopeExists := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) - if ctx.Data["IsApiToken"] != true || !scopeExists { + if !scopeExists { return } diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go index 96aa0ce258c..0448a1961b4 100644 --- a/routers/api/v1/repo/release.go +++ b/routers/api/v1/repo/release.go @@ -23,12 +23,11 @@ func canAccessReleaseDraft(ctx *context.APIContext) bool { if !ctx.IsSigned || !ctx.Repo.Permission.CanWrite(unit.TypeReleases) { return false } - if ctx.Data["IsApiToken"] != true { + scope, hasApiTokenScope := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) + if !hasApiTokenScope { // not API token request, the request is from a user session with write access return true } - // the request is from an access token with scope - scope := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) //nolint:forcetypeassert // must exist requiredScopes := auth_model.GetRequiredScopes(auth_model.Write, auth_model.AccessTokenScopeCategoryRepository) allow, _ := scope.HasScope(requiredScopes...) // err (invalid token) can be safely ignored return allow diff --git a/routers/api/v1/user/app.go b/routers/api/v1/user/app.go index c7749b0951b..5c1ab20464a 100644 --- a/routers/api/v1/user/app.go +++ b/routers/api/v1/user/app.go @@ -127,12 +127,8 @@ func CreateAccessToken(ctx *context.APIContext) { t.Scope = scope // a token-authenticated request must not mint a token with a broader scope than its own - if ctx.Data["IsApiToken"] == true { - apiTokenScope, ok := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) - if !ok { - ctx.APIError(http.StatusForbidden, "the authenticating token has no scope") - return - } + apiTokenScope, hasApiTokenScope := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) + if hasApiTokenScope { hasScope, err := apiTokenScope.CanCreateChildScope(scope) if err != nil { ctx.APIErrorInternal(err) diff --git a/routers/web/goget.go b/routers/web/goget.go index 256d755beb7..922e9cc13e4 100644 --- a/routers/web/goget.go +++ b/routers/web/goget.go @@ -127,13 +127,10 @@ func goGetDefaultBranch(ctx *context.Context, repo *repo_model.Repository) strin // always may; a token request may only when its scope grants repository read, so a PAT that was never // scoped for repositories cannot disclose the branch even if its owner can read the repo. func goGetTokenCanReadRepo(ctx *context.Context) bool { - if ctx.Data["IsApiToken"] != true { + scope, hasApiTokenScope := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) + if !hasApiTokenScope { return true } - scope, ok := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) - if !ok { - return false - } has, err := scope.HasScope(auth_model.AccessTokenScopeReadRepository) return err == nil && has } diff --git a/routers/web/repo/githttp.go b/routers/web/repo/githttp.go index da8c09f919a..f45155568e4 100644 --- a/routers/web/repo/githttp.go +++ b/routers/web/repo/githttp.go @@ -163,7 +163,7 @@ func httpBase(ctx *context.Context, optGitService ...string) *serviceHandler { return nil } - if ctx.IsBasicAuth && ctx.Data["IsApiToken"] != true && !ctx.Doer.IsGiteaActions() { + if ctx.IsBasicAuth && ctx.Data["ApiTokenScope"] == nil && !ctx.Doer.IsGiteaActions() { _, err = auth_model.GetTwoFactorByUID(ctx, 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 diff --git a/routers/web/user/setting/applications.go b/routers/web/user/setting/applications.go index 942e753c2fe..6347d8ebdfb 100644 --- a/routers/web/user/setting/applications.go +++ b/routers/web/user/setting/applications.go @@ -82,12 +82,8 @@ func ApplicationsPost(ctx *context.Context) { // a token-authenticated request must not mint a token with a broader scope than its own, nor // drop the public-only restriction. Web routes accept basic-auth PATs/OAuth tokens too, so this // must mirror the REST API guard in routers/api/v1/user/app.go. - if ctx.Data["IsApiToken"] == true { - apiTokenScope, ok := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) - if !ok { - ctx.HTTPError(http.StatusForbidden, "the authenticating token has no scope") - return - } + apiTokenScope, hasApiTokenScope := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) + if hasApiTokenScope { hasScope, err := apiTokenScope.CanCreateChildScope(t.Scope) if err != nil { ctx.ServerError("CanCreateChildScope", err) diff --git a/services/auth/basic.go b/services/auth/basic.go index 8ef6333c210..e0825f88753 100644 --- a/services/auth/basic.go +++ b/services/auth/basic.go @@ -81,7 +81,6 @@ func (b *Basic) VerifyAuthToken(req *http.Request, w http.ResponseWriter, store } store.GetData()["LoginMethod"] = OAuth2TokenMethodName - store.GetData()["IsApiToken"] = true store.GetData()["ApiTokenScope"] = accessTokenScope return u, nil } @@ -102,7 +101,6 @@ func (b *Basic) VerifyAuthToken(req *http.Request, w http.ResponseWriter, store } store.GetData()["LoginMethod"] = AccessTokenMethodName - store.GetData()["IsApiToken"] = true store.GetData()["ApiTokenScope"] = token.Scope return u, nil } else if !errors.Is(err, util.ErrNotExist) { @@ -187,7 +185,7 @@ func validateTOTP(req *http.Request, u *user_model.User) error { } func GetAccessScope(store DataStore) auth_model.AccessTokenScope { - if scope, ok := store.GetData()["ApiTokenScope"].(auth_model.AccessTokenScope); ok { + if scope, hasApiTokenScope := store.GetData()["ApiTokenScope"].(auth_model.AccessTokenScope); hasApiTokenScope { return scope } switch store.GetData()["LoginMethod"] { diff --git a/services/auth/httpsign.go b/services/auth/httpsign.go index 5e1325db603..7ce7cc64216 100644 --- a/services/auth/httpsign.go +++ b/services/auth/httpsign.go @@ -77,9 +77,6 @@ func (h *HTTPSign) Verify(req *http.Request, w http.ResponseWriter, store DataSt log.Error("GetUserByID: %v", err) return nil, err } - - store.GetData()["IsApiToken"] = true - log.Trace("HTTP Sign: Logged in user %-v", u) return u, nil diff --git a/services/auth/oauth2.go b/services/auth/oauth2.go index cb622c22581..0b2ac89d6d2 100644 --- a/services/auth/oauth2.go +++ b/services/auth/oauth2.go @@ -106,8 +106,7 @@ func parseToken(req *http.Request) (string, bool) { } // userFromToken returns the user corresponding to the OAuth token. -// It will set 'IsApiToken' to true if the token is an API token and -// set 'ApiTokenScope' to the scope of the access token (TODO: this behavior should be fixed, don't set ctx.Data) +// It will set 'ApiTokenScope' to the scope of the access token (TODO: this behavior should be fixed, don't set ctx.Data) func (o *OAuth2) userFromToken(ctx context.Context, tokenSHA string, store DataStore) (*user_model.User, error) { // Let's see if token is valid. if strings.Contains(tokenSHA, ".") { @@ -121,7 +120,6 @@ func (o *OAuth2) userFromToken(ctx context.Context, tokenSHA string, store DataS // Otherwise, check if this is an OAuth access token accessTokenScope, uid := GetOAuthAccessTokenScopeAndUserID(ctx, tokenSHA) if uid != 0 { - store.GetData()["IsApiToken"] = true store.GetData()["ApiTokenScope"] = accessTokenScope } return user_model.GetUserByID(ctx, uid) @@ -142,7 +140,6 @@ func (o *OAuth2) userFromToken(ctx context.Context, tokenSHA string, store DataS if err = auth_model.UpdateAccessToken(ctx, t); err != nil { log.Error("UpdateAccessToken: %v", err) } - store.GetData()["IsApiToken"] = true store.GetData()["ApiTokenScope"] = t.Scope return user_model.GetUserByID(ctx, t.UID) } diff --git a/services/context/permission.go b/services/context/permission.go index f0c93081c6a..97963461685 100644 --- a/services/context/permission.go +++ b/services/context/permission.go @@ -35,11 +35,8 @@ func publicOnlyTokenDeniedRepo(ctx context.Context, repo *repo_model.Repository) // TokenIsPublicOnly reports whether the request is authenticated by a public-only API token. A // non-token request, or a token with no recorded scope, is not public-only. func TokenIsPublicOnly(ctx *Context) bool { - if ctx.Data["IsApiToken"] != true { - return false - } - scope, ok := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) - if !ok { + scope, hasApiTokenScope := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) + if !hasApiTokenScope { return false } publicOnly, _ := scope.PublicOnly() @@ -48,12 +45,8 @@ func TokenIsPublicOnly(ctx *Context) bool { // CheckTokenScopes checks whether the authenticated API token contains any of the given scopes. func CheckTokenScopes(ctx *Context, repo *repo_model.Repository, scopes ...auth_model.AccessTokenScope) { - if ctx.Data["IsApiToken"] != true { - return - } - - scope, ok := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) - if !ok { + scope, hasApiTokenScope := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope) + if !hasApiTokenScope { return }