mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-23 16:44:41 +02:00
fix: validate "scope" for OAuth2, "state" for OpenID (#39642)
1. Fixes: https://github.com/go-gitea/gitea/issues/39641 * The OAuth2 authorize/grant endpoint accepted and persisted arbitrary scope strings without validation, unlike personal access token creation which rejects unknown scopes. Normalize and validate form.Scope before creating or updating a grant, ignore invalid scopes * `// TODO: at the moment invalid tokens are treated as "all" to avoid breaking 1.22 behavior` is fixed. 2. To avoid CSRF attack for OpenID endpoint, add a state check --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
1 parent
4b5f1f46de
commit
f270534e83
9 files changed
+257
-57
No files matched your search
@@ -54,7 +54,8 @@ type AccessTokenScope string
|
||||
// for all categories, write implies read
|
||||
const (
|
||||
AccessTokenScopeAll AccessTokenScope = "all"
|
||||
AccessTokenScopePublicOnly AccessTokenScope = "public-only" // limited to public orgs/repos
|
||||
AccessTokenScopeNone AccessTokenScope = "no-token-scope" // no token permission scopes, so no API permissions
|
||||
AccessTokenScopePublicOnly AccessTokenScope = "public-only" // limited to public orgs/repos
|
||||
|
||||
AccessTokenScopeReadActivityPub AccessTokenScope = "read:activitypub"
|
||||
AccessTokenScopeWriteActivityPub AccessTokenScope = "write:activitypub"
|
||||
@@ -147,6 +148,7 @@ var allAccessTokenScopes = []AccessTokenScope{
|
||||
// allAccessTokenScopeBits contains all access token scopes.
|
||||
var allAccessTokenScopeBits = map[AccessTokenScope]accessTokenScopeBitmap{
|
||||
AccessTokenScopeAll: accessTokenScopeAllBits,
|
||||
AccessTokenScopeNone: 0,
|
||||
AccessTokenScopePublicOnly: accessTokenScopePublicOnlyBits,
|
||||
AccessTokenScopeReadActivityPub: accessTokenScopeReadActivityPubBits,
|
||||
AccessTokenScopeWriteActivityPub: accessTokenScopeWriteActivityPubBits,
|
||||
@@ -211,11 +213,6 @@ func GetRequiredScopes(level AccessTokenScopeLevel, scopeCategories ...AccessTok
|
||||
return scopes
|
||||
}
|
||||
|
||||
// ContainsCategory checks if a list of categories contains a specific category
|
||||
func ContainsCategory(categories []AccessTokenScopeCategory, category AccessTokenScopeCategory) bool {
|
||||
return slices.Contains(categories, category)
|
||||
}
|
||||
|
||||
// GetScopeLevelFromAccessMode converts permission access mode to scope level
|
||||
func GetScopeLevelFromAccessMode(mode perm.AccessMode) AccessTokenScopeLevel {
|
||||
switch mode {
|
||||
@@ -286,12 +283,14 @@ func (s AccessTokenScope) Normalize() (AccessTokenScope, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if bitmap == 0 && slices.Contains(s.StringSlice(), string(AccessTokenScopeNone)) {
|
||||
return AccessTokenScopeNone, nil
|
||||
}
|
||||
return bitmap.toScope(), nil
|
||||
}
|
||||
|
||||
func (s AccessTokenScope) HasPermissionScope() bool {
|
||||
return s != "" && s != AccessTokenScopePublicOnly
|
||||
return s != "" && s != AccessTokenScopeNone && s != AccessTokenScopePublicOnly
|
||||
}
|
||||
|
||||
// PublicOnly checks if this token scope is limited to public resources
|
||||
|
||||
@@ -18,8 +18,14 @@ type scopeTestNormalize struct {
|
||||
|
||||
func TestAccessTokenScope_Normalize(t *testing.T) {
|
||||
assert.Equal(t, []string{"activitypub", "admin", "issue", "misc", "notification", "organization", "package", "repository", "user"}, GetAccessTokenCategories())
|
||||
assert.False(t, AccessTokenScopeNone.HasPermissionScope())
|
||||
tests := []scopeTestNormalize{
|
||||
{"", "", nil},
|
||||
{"no-token-scope", "no-token-scope", nil},
|
||||
{"no-token-scope,no-token-scope", "no-token-scope", nil},
|
||||
{"no-token-scope,read:user", "read:user", nil},
|
||||
{"no-token-scope,public-only", "public-only", nil},
|
||||
{"no-token-scope,all", "all", nil},
|
||||
{"write:misc,write:notification,read:package,write:notification,public-only", "public-only,write:misc,write:notification,read:package", nil},
|
||||
{"all", "all", nil},
|
||||
{"write:activitypub,write:admin,write:misc,write:notification,write:organization,write:package,write:issue,write:repository,write:user", "all", nil},
|
||||
@@ -58,10 +64,20 @@ func TestAccessTokenScope_HasScope(t *testing.T) {
|
||||
{"all", "write:package", true, nil},
|
||||
{"write:package", "all", false, nil},
|
||||
{"public-only", "read:issue", false, nil},
|
||||
{"no-token-scope", "all", false, nil},
|
||||
{"no-token-scope", "no-token-scope", true, nil},
|
||||
}
|
||||
|
||||
for _, scope := range GetAccessTokenCategories() {
|
||||
tests = append(tests,
|
||||
scopeTestHasScope{
|
||||
AccessTokenScopeNone,
|
||||
AccessTokenScope("read:" + scope), false, nil,
|
||||
},
|
||||
scopeTestHasScope{
|
||||
AccessTokenScopeNone,
|
||||
AccessTokenScope("write:" + scope), false, nil,
|
||||
},
|
||||
scopeTestHasScope{
|
||||
AccessTokenScope("read:" + scope),
|
||||
AccessTokenScope("read:" + scope), true, nil,
|
||||
|
||||
Reference in new issue
Block a user