mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-12 19:50:51 +00:00
refactor: api token scope check (#38862)
"ApiTokenScope" already means "IsApiToken=true". All "IsApiToken" should be removed. --------- Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"] {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user