-
-
Notifications
You must be signed in to change notification settings - Fork 5.8k
Support scoped access tokens #20908
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Support scoped access tokens #20908
Changes from all commits
Commits
Show all changes
152 commits
Select commit
Hold shift + click to select a range
90e3b58
Add scope field to access token
harryzcy 89d1140
Add token scope helper functions
harryzcy 0933496
Add comments
harryzcy 948cd14
Move token_scope file to models/auth
harryzcy fd6e821
Include copyright
harryzcy b013747
Add more unit tests
harryzcy 794484a
Support 'all' scope
harryzcy ad3ff54
Support checking scope access
harryzcy 6c5dd10
Restrict scope for some APIs
harryzcy cd13850
Let repo scope to cover admin:repo_hook
harryzcy 745ec98
Add sudo scope
harryzcy 74b4871
Add more scope requirements
harryzcy 6f4eed0
Add token selection UI
harryzcy 4fd1722
Update access token form
harryzcy 4476e1d
Fix integration tests for api_branch
harryzcy 86341c5
Fix ending newline for a template
harryzcy cfcbdba
Update the types for ApiTokenScope in context
harryzcy 4b570b8
Parse scope for request when adding a token
harryzcy 1ebfc83
Fix GetScope method
harryzcy b751682
Normalize scope before storing in database
harryzcy 17f3183
Fix many integration test issues
harryzcy f83dc7d
Merge branch 'main' into access-token-scope
harryzcy 85db585
Merge branch 'main' into access-token-scope
harryzcy fca8b79
Merge branch 'main' into access-token-scope
harryzcy f3942ef
Revert api router and integration tests
harryzcy fafc36d
Support specifying scope in reqToken
harryzcy 06e9c81
Support getting scoped token in integration tests
harryzcy be5164b
Restrict token scope for notifications
harryzcy 9f7db16
Add notification scope to TestEventSourceManagerRun
harryzcy 4464289
Add scope to 'user' api
harryzcy 800de93
Fix gpg key token tests
harryzcy 1fe42fb
Add repo scope to user/applications
harryzcy 32cac39
Fix gpg key token name in web
harryzcy 99f30f6
Add more repo scope to integration tests
harryzcy f839856
Fix git tests
harryzcy 0583e79
Add gpg key scope to a user test
harryzcy a282f02
Limit token scope for some repo APIs
harryzcy 0bee969
Add repo scope in TestGPGKeys
harryzcy 182b984
Fix repo scope in TestGPGKeys again
harryzcy 965de53
Fix more repo scope issues
harryzcy f376275
Fix the token for repo hooks
harryzcy 0a837e7
Include repo scope in TestAPIReposRaw
harryzcy a44f62e
Add repo scope to TestAPIRepoTeams
harryzcy 755faf6
Fix more integration tests
harryzcy b4c35e8
Fix typos that causes errors
harryzcy 0ff93b8
Add fixes for delete_repo scope
harryzcy 37c59c9
There are so many fixes
harryzcy f13904a
Reuse code in `modules/util`
harryzcy 7a3b165
Include copyright statement
harryzcy 62c9f70
Limit repo scope on /api/v1/{user}/{repo}/issues
harryzcy 15ed960
Fix several integration tests
harryzcy 11a5103
Include repo scope in TestMigrateGiteaForm
harryzcy 290b63d
Merge branch 'main' into access-token-scope
harryzcy d6d6d97
Apply repo scope to more APIs
harryzcy 0a8ab09
Restrict repo scope to remaining repos endpoints
harryzcy f45bfe3
No token needed for some public info
harryzcy 0f25b04
Cleanup one duplicated reqToken call
harryzcy f76259b
Add package scope for package APIs
harryzcy 6d7e7e5
Fix package integration tests
harryzcy 9f2af77
Merge branch 'main' into access-token-scope
harryzcy e8af871
Limit scope for `/api/v1/orgs`
harryzcy dc6ac14
Fix some test but still have works to do
harryzcy 853eb68
One more fix
harryzcy 45f716f
Fix the scope required for /api/v1/orgs/{org}/teams
harryzcy 8b0bc32
Disallow unauthenticated call to users/{user}/orgs
harryzcy 8f03691
Fix TestAPIGetAll
harryzcy b6f6ad4
Merge branch 'main' into access-token-scope
harryzcy 2451acc
Add scope to teams APIs
harryzcy 93fbca3
Ensure token exists before running reqTeamMembership
harryzcy a10b8dc
Add sudo token to /admin API
harryzcy 99f05e8
Support public_repo scope
harryzcy 8e45f81
Introduce database migration
harryzcy af08a1e
Run make fmt
harryzcy a48d07d
Merge remote-tracking branch 'upstream/main' into access-token-scope
harryzcy 9a63bb9
Copy and define struct definition in migrations
harryzcy 184cf7c
Merge remote-tracking branch 'upstream/main' into access-token-scope
harryzcy 45d0c22
Update migration description
harryzcy fa00b5e
Merge remote-tracking branch 'upstream/main' into access-token-scope
harryzcy 32fa981
Fix test error introduced by merge commits
harryzcy 13cd621
List only the modified fields in migration
harryzcy 525c11d
Merge branch 'main' into access-token-scope
6543 f99cb7f
Restore a test for comments api
harryzcy 7706cb3
Fix linting issues
harryzcy 38da63a
Migrate without default and update old records
harryzcy bef352a
Update httpsig test
harryzcy d60b20b
Allow auth via signatures for admin apis
harryzcy 191f3b4
Remove token in TestHTTPSigCert
harryzcy de66220
Remove unused function
harryzcy 071fe39
Fix failing tests
harryzcy 9123e54
Update integration tests
harryzcy e412003
Merge branch 'main' into access-token-scope
harryzcy 9b662fe
Update routers/api/v1/api.go
harryzcy e755747
Add admin:application scope
harryzcy 143c851
Fix unit testing
harryzcy be84669
Update token scope of `/api/v1/user/applications`
harryzcy cd1e422
Update comment
harryzcy 28b1326
Update frontend to add the new scope
harryzcy 4f38d44
Fix auth functions to allow either token or sigs
harryzcy fb9b97f
Merge branch 'main' into access-token-scope
harryzcy 9abd5ab
[doc] Add token scopes doc
harryzcy 0ddab28
Fix `repo:status` token
harryzcy 0883603
Rewrite scope logic to let write:* contain read:*
harryzcy bd81d43
Merge branch 'main' into access-token-scope
harryzcy 2af8768
Use constant `AccessTokenScopeSudo` in api.go
harryzcy bb4a64b
Merge branch 'main' into access-token-scope
harryzcy 50a3c5f
Update access token form and update tests to use constants
harryzcy 7c4ecf4
Fix lint issue
harryzcy dc1a717
Fix TestAPIOrgDeny
harryzcy 633ca9e
Merge branch 'main' into access-token-scope
harryzcy 240656a
Catch missed constants
harryzcy ed97ed0
Merge branch 'main' into access-token-scope
harryzcy c648db2
Merge remote-tracking branch 'upstream/main' into access-token-scope
harryzcy b1ddfea
Document current implementation limitation
harryzcy 826b160
Update copyright style
harryzcy 0e0c4dd
Ensure migration is safe
harryzcy 5238a4d
Merge branch 'main' into access-token-scope
harryzcy 3b93df8
Fix integration tests after merge
harryzcy 16b13a7
Use Forbidden for tokens without required scope
harryzcy 0cecf88
Merge branch 'main' into access-token-scope
harryzcy 5f70625
Fix indentation issue
harryzcy 991e965
Merge branch 'main' into access-token-scope
harryzcy 5f0076c
Fix data race in integration tests
harryzcy 73dff67
Merge branch 'main' into access-token-scope
harryzcy 5fecbd1
Fix License header issue
harryzcy 3c8be2e
Fix tests errors caused by merge
harryzcy 730231c
Merge branch 'main' into access-token-scope
harryzcy 6b89fe7
Merge branch 'main' into access-token-scope
harryzcy 0e4063a
Merge branch 'main' into access-token-scope
harryzcy 4caafb6
Merge branch 'main' into access-token-scope
harryzcy a7340b8
Prevent `IsApiToken` change
harryzcy 6796f66
Fix integration tests after merging from upstream
harryzcy 21e5063
Merge branch 'main' into access-token-scope
harryzcy e5d0e33
Merge branch 'main' into access-token-scope
harryzcy a1b52e4
Document all token scopes
harryzcy e3114bb
Update docs/content/doc/developers/oauth2-provider.en-us.md
harryzcy 620df8d
Merge branch 'main' into access-token-scope
harryzcy 7beea96
Merge branch 'main' into access-token-scope
harryzcy c80cc09
Merge branch 'main' into access-token-scope
harryzcy 6ffebec
Merge branch 'main' into access-token-scope
harryzcy cd836c7
Use map to store token scope bits
harryzcy 70d0c83
Use custom type for all scope variables
harryzcy bce707f
Fix backend lints
harryzcy d0a27a6
Update types for bitmap constants as well
harryzcy 64d5251
Fix typing issue in integration tests
harryzcy 32fa0aa
Fix type in router APIs
harryzcy 0d9160b
Avoid unnecessary type conversion
harryzcy 7d7344f
More unnecessary conversion
harryzcy 6f2974a
Include sudo scope for old tokens during migration
harryzcy 6275a9d
Merge branch 'main' into access-token-scope
harryzcy 1f596e7
Use string type in migration
harryzcy 3a3ef8f
Merge branch 'main' into access-token-scope
lunny 49aba97
Merge branch 'main' into access-token-scope
jolheiser File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,251 @@ | ||
// Copyright 2022 The Gitea Authors. All rights reserved. | ||
// SPDX-License-Identifier: MIT | ||
|
||
package auth | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
) | ||
|
||
// AccessTokenScope represents the scope for an access token. | ||
type AccessTokenScope string | ||
|
||
const ( | ||
AccessTokenScopeAll AccessTokenScope = "all" | ||
|
||
AccessTokenScopeRepo AccessTokenScope = "repo" | ||
AccessTokenScopeRepoStatus AccessTokenScope = "repo:status" | ||
AccessTokenScopePublicRepo AccessTokenScope = "public_repo" | ||
|
||
AccessTokenScopeAdminOrg AccessTokenScope = "admin:org" | ||
AccessTokenScopeWriteOrg AccessTokenScope = "write:org" | ||
AccessTokenScopeReadOrg AccessTokenScope = "read:org" | ||
|
||
AccessTokenScopeAdminPublicKey AccessTokenScope = "admin:public_key" | ||
AccessTokenScopeWritePublicKey AccessTokenScope = "write:public_key" | ||
AccessTokenScopeReadPublicKey AccessTokenScope = "read:public_key" | ||
|
||
AccessTokenScopeAdminRepoHook AccessTokenScope = "admin:repo_hook" | ||
AccessTokenScopeWriteRepoHook AccessTokenScope = "write:repo_hook" | ||
AccessTokenScopeReadRepoHook AccessTokenScope = "read:repo_hook" | ||
|
||
AccessTokenScopeAdminOrgHook AccessTokenScope = "admin:org_hook" | ||
|
||
AccessTokenScopeNotification AccessTokenScope = "notification" | ||
|
||
AccessTokenScopeUser AccessTokenScope = "user" | ||
AccessTokenScopeReadUser AccessTokenScope = "read:user" | ||
AccessTokenScopeUserEmail AccessTokenScope = "user:email" | ||
AccessTokenScopeUserFollow AccessTokenScope = "user:follow" | ||
|
||
AccessTokenScopeDeleteRepo AccessTokenScope = "delete_repo" | ||
|
||
AccessTokenScopePackage AccessTokenScope = "package" | ||
AccessTokenScopeWritePackage AccessTokenScope = "write:package" | ||
AccessTokenScopeReadPackage AccessTokenScope = "read:package" | ||
AccessTokenScopeDeletePackage AccessTokenScope = "delete:package" | ||
|
||
AccessTokenScopeAdminGPGKey AccessTokenScope = "admin:gpg_key" | ||
AccessTokenScopeWriteGPGKey AccessTokenScope = "write:gpg_key" | ||
AccessTokenScopeReadGPGKey AccessTokenScope = "read:gpg_key" | ||
|
||
AccessTokenScopeAdminApplication AccessTokenScope = "admin:application" | ||
AccessTokenScopeWriteApplication AccessTokenScope = "write:application" | ||
AccessTokenScopeReadApplication AccessTokenScope = "read:application" | ||
|
||
AccessTokenScopeSudo AccessTokenScope = "sudo" | ||
) | ||
|
||
// AccessTokenScopeBitmap represents a bitmap of access token scopes. | ||
type AccessTokenScopeBitmap uint64 | ||
|
||
// Bitmap of each scope, including the child scopes. | ||
const ( | ||
// AccessTokenScopeAllBits is the bitmap of all access token scopes, except `sudo`. | ||
AccessTokenScopeAllBits AccessTokenScopeBitmap = AccessTokenScopeRepoBits | | ||
AccessTokenScopeAdminOrgBits | AccessTokenScopeAdminPublicKeyBits | AccessTokenScopeAdminOrgHookBits | | ||
AccessTokenScopeNotificationBits | AccessTokenScopeUserBits | AccessTokenScopeDeleteRepoBits | | ||
AccessTokenScopePackageBits | AccessTokenScopeAdminGPGKeyBits | AccessTokenScopeAdminApplicationBits | ||
|
||
AccessTokenScopeRepoBits AccessTokenScopeBitmap = 1<<iota | AccessTokenScopeRepoStatusBits | AccessTokenScopePublicRepoBits | AccessTokenScopeAdminRepoHookBits | ||
AccessTokenScopeRepoStatusBits AccessTokenScopeBitmap = 1 << iota | ||
AccessTokenScopePublicRepoBits AccessTokenScopeBitmap = 1 << iota | ||
|
||
AccessTokenScopeAdminOrgBits AccessTokenScopeBitmap = 1<<iota | AccessTokenScopeWriteOrgBits | ||
AccessTokenScopeWriteOrgBits AccessTokenScopeBitmap = 1<<iota | AccessTokenScopeReadOrgBits | ||
AccessTokenScopeReadOrgBits AccessTokenScopeBitmap = 1 << iota | ||
|
||
AccessTokenScopeAdminPublicKeyBits AccessTokenScopeBitmap = 1<<iota | AccessTokenScopeWritePublicKeyBits | ||
AccessTokenScopeWritePublicKeyBits AccessTokenScopeBitmap = 1<<iota | AccessTokenScopeReadPublicKeyBits | ||
AccessTokenScopeReadPublicKeyBits AccessTokenScopeBitmap = 1 << iota | ||
|
||
AccessTokenScopeAdminRepoHookBits AccessTokenScopeBitmap = 1<<iota | AccessTokenScopeWriteRepoHookBits | ||
AccessTokenScopeWriteRepoHookBits AccessTokenScopeBitmap = 1<<iota | AccessTokenScopeReadRepoHookBits | ||
AccessTokenScopeReadRepoHookBits AccessTokenScopeBitmap = 1 << iota | ||
|
||
AccessTokenScopeAdminOrgHookBits AccessTokenScopeBitmap = 1 << iota | ||
|
||
AccessTokenScopeNotificationBits AccessTokenScopeBitmap = 1 << iota | ||
|
||
AccessTokenScopeUserBits AccessTokenScopeBitmap = 1<<iota | AccessTokenScopeReadUserBits | AccessTokenScopeUserEmailBits | AccessTokenScopeUserFollowBits | ||
AccessTokenScopeReadUserBits AccessTokenScopeBitmap = 1 << iota | ||
AccessTokenScopeUserEmailBits AccessTokenScopeBitmap = 1 << iota | ||
AccessTokenScopeUserFollowBits AccessTokenScopeBitmap = 1 << iota | ||
|
||
AccessTokenScopeDeleteRepoBits AccessTokenScopeBitmap = 1 << iota | ||
|
||
AccessTokenScopePackageBits AccessTokenScopeBitmap = 1<<iota | AccessTokenScopeWritePackageBits | AccessTokenScopeDeletePackageBits | ||
AccessTokenScopeWritePackageBits AccessTokenScopeBitmap = 1<<iota | AccessTokenScopeReadPackageBits | ||
AccessTokenScopeReadPackageBits AccessTokenScopeBitmap = 1 << iota | ||
AccessTokenScopeDeletePackageBits AccessTokenScopeBitmap = 1 << iota | ||
|
||
AccessTokenScopeAdminGPGKeyBits AccessTokenScopeBitmap = 1<<iota | AccessTokenScopeWriteGPGKeyBits | ||
AccessTokenScopeWriteGPGKeyBits AccessTokenScopeBitmap = 1<<iota | AccessTokenScopeReadGPGKeyBits | ||
AccessTokenScopeReadGPGKeyBits AccessTokenScopeBitmap = 1 << iota | ||
|
||
AccessTokenScopeAdminApplicationBits AccessTokenScopeBitmap = 1<<iota | AccessTokenScopeWriteApplicationBits | ||
AccessTokenScopeWriteApplicationBits AccessTokenScopeBitmap = 1<<iota | AccessTokenScopeReadApplicationBits | ||
AccessTokenScopeReadApplicationBits AccessTokenScopeBitmap = 1 << iota | ||
|
||
AccessTokenScopeSudoBits AccessTokenScopeBitmap = 1 << iota | ||
|
||
// The current implementation only supports up to 64 token scopes. | ||
// If we need to support > 64 scopes, | ||
// refactoring the whole implementation in this file (and only this file) is needed. | ||
) | ||
|
||
// allAccessTokenScopes contains all access token scopes. | ||
// The order is important: parent scope must precedes child scopes. | ||
var allAccessTokenScopes = []AccessTokenScope{ | ||
AccessTokenScopeRepo, AccessTokenScopeRepoStatus, AccessTokenScopePublicRepo, | ||
AccessTokenScopeAdminOrg, AccessTokenScopeWriteOrg, AccessTokenScopeReadOrg, | ||
AccessTokenScopeAdminPublicKey, AccessTokenScopeWritePublicKey, AccessTokenScopeReadPublicKey, | ||
AccessTokenScopeAdminRepoHook, AccessTokenScopeWriteRepoHook, AccessTokenScopeReadRepoHook, | ||
AccessTokenScopeAdminOrgHook, | ||
AccessTokenScopeNotification, | ||
AccessTokenScopeUser, AccessTokenScopeReadUser, AccessTokenScopeUserEmail, AccessTokenScopeUserFollow, | ||
AccessTokenScopeDeleteRepo, | ||
AccessTokenScopePackage, AccessTokenScopeWritePackage, AccessTokenScopeReadPackage, AccessTokenScopeDeletePackage, | ||
AccessTokenScopeAdminGPGKey, AccessTokenScopeWriteGPGKey, AccessTokenScopeReadGPGKey, | ||
AccessTokenScopeAdminApplication, AccessTokenScopeWriteApplication, AccessTokenScopeReadApplication, | ||
AccessTokenScopeSudo, | ||
} | ||
|
||
// allAccessTokenScopeBits contains all access token scopes. | ||
var allAccessTokenScopeBits = map[AccessTokenScope]AccessTokenScopeBitmap{ | ||
AccessTokenScopeRepo: AccessTokenScopeRepoBits, | ||
AccessTokenScopeRepoStatus: AccessTokenScopeRepoStatusBits, | ||
AccessTokenScopePublicRepo: AccessTokenScopePublicRepoBits, | ||
AccessTokenScopeAdminOrg: AccessTokenScopeAdminOrgBits, | ||
AccessTokenScopeWriteOrg: AccessTokenScopeWriteOrgBits, | ||
AccessTokenScopeReadOrg: AccessTokenScopeReadOrgBits, | ||
AccessTokenScopeAdminPublicKey: AccessTokenScopeAdminPublicKeyBits, | ||
AccessTokenScopeWritePublicKey: AccessTokenScopeWritePublicKeyBits, | ||
AccessTokenScopeReadPublicKey: AccessTokenScopeReadPublicKeyBits, | ||
AccessTokenScopeAdminRepoHook: AccessTokenScopeAdminRepoHookBits, | ||
AccessTokenScopeWriteRepoHook: AccessTokenScopeWriteRepoHookBits, | ||
AccessTokenScopeReadRepoHook: AccessTokenScopeReadRepoHookBits, | ||
AccessTokenScopeAdminOrgHook: AccessTokenScopeAdminOrgHookBits, | ||
AccessTokenScopeNotification: AccessTokenScopeNotificationBits, | ||
AccessTokenScopeUser: AccessTokenScopeUserBits, | ||
AccessTokenScopeReadUser: AccessTokenScopeReadUserBits, | ||
AccessTokenScopeUserEmail: AccessTokenScopeUserEmailBits, | ||
AccessTokenScopeUserFollow: AccessTokenScopeUserFollowBits, | ||
AccessTokenScopeDeleteRepo: AccessTokenScopeDeleteRepoBits, | ||
AccessTokenScopePackage: AccessTokenScopePackageBits, | ||
AccessTokenScopeWritePackage: AccessTokenScopeWritePackageBits, | ||
AccessTokenScopeReadPackage: AccessTokenScopeReadPackageBits, | ||
AccessTokenScopeDeletePackage: AccessTokenScopeDeletePackageBits, | ||
AccessTokenScopeAdminGPGKey: AccessTokenScopeAdminGPGKeyBits, | ||
AccessTokenScopeWriteGPGKey: AccessTokenScopeWriteGPGKeyBits, | ||
AccessTokenScopeReadGPGKey: AccessTokenScopeReadGPGKeyBits, | ||
AccessTokenScopeAdminApplication: AccessTokenScopeAdminApplicationBits, | ||
AccessTokenScopeWriteApplication: AccessTokenScopeWriteApplicationBits, | ||
AccessTokenScopeReadApplication: AccessTokenScopeReadApplicationBits, | ||
AccessTokenScopeSudo: AccessTokenScopeSudoBits, | ||
} | ||
|
||
// Parse parses the scope string into a bitmap, thus removing possible duplicates. | ||
func (s AccessTokenScope) Parse() (AccessTokenScopeBitmap, error) { | ||
list := strings.Split(string(s), ",") | ||
|
||
var bitmap AccessTokenScopeBitmap | ||
for _, v := range list { | ||
singleScope := AccessTokenScope(v) | ||
if singleScope == "" { | ||
continue | ||
} | ||
if singleScope == AccessTokenScopeAll { | ||
bitmap |= AccessTokenScopeAllBits | ||
continue | ||
} | ||
|
||
bits, ok := allAccessTokenScopeBits[singleScope] | ||
if !ok { | ||
return 0, fmt.Errorf("invalid access token scope: %s", singleScope) | ||
} | ||
bitmap |= bits | ||
} | ||
return bitmap, nil | ||
} | ||
|
||
// Normalize returns a normalized scope string without any duplicates. | ||
func (s AccessTokenScope) Normalize() (AccessTokenScope, error) { | ||
bitmap, err := s.Parse() | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return bitmap.ToScope(), nil | ||
} | ||
|
||
// HasScope returns true if the string has the given scope | ||
func (s AccessTokenScope) HasScope(scope AccessTokenScope) (bool, error) { | ||
bitmap, err := s.Parse() | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
return bitmap.HasScope(scope) | ||
} | ||
|
||
// HasScope returns true if the string has the given scope | ||
func (bitmap AccessTokenScopeBitmap) HasScope(scope AccessTokenScope) (bool, error) { | ||
expectedBits, ok := allAccessTokenScopeBits[scope] | ||
if !ok { | ||
return false, fmt.Errorf("invalid access token scope: %s", scope) | ||
} | ||
|
||
return bitmap&expectedBits == expectedBits, nil | ||
} | ||
|
||
// ToScope returns a normalized scope string without any duplicates. | ||
func (bitmap AccessTokenScopeBitmap) ToScope() AccessTokenScope { | ||
var scopes []string | ||
|
||
// iterate over all scopes, and reconstruct the bitmap | ||
// if the reconstructed bitmap doesn't change, then the scope is already included | ||
var reconstruct AccessTokenScopeBitmap | ||
|
||
for _, singleScope := range allAccessTokenScopes { | ||
// no need for error checking here, since we know the scope is valid | ||
if ok, _ := bitmap.HasScope(singleScope); ok { | ||
current := reconstruct | allAccessTokenScopeBits[singleScope] | ||
if current == reconstruct { | ||
continue | ||
} | ||
|
||
reconstruct = current | ||
scopes = append(scopes, string(singleScope)) | ||
} | ||
} | ||
|
||
scope := AccessTokenScope(strings.Join(scopes, ",")) | ||
scope = AccessTokenScope(strings.ReplaceAll( | ||
string(scope), | ||
"repo,admin:org,admin:public_key,admin:org_hook,notification,user,delete_repo,package,admin:gpg_key,admin:application", | ||
"all", | ||
)) | ||
return scope | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// Copyright 2022 The Gitea Authors. All rights reserved. | ||
// SPDX-License-Identifier: MIT | ||
|
||
package auth | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestAccessTokenScope_Normalize(t *testing.T) { | ||
tests := []struct { | ||
in AccessTokenScope | ||
out AccessTokenScope | ||
err error | ||
}{ | ||
{"", "", nil}, | ||
{"repo", "repo", nil}, | ||
{"repo,repo:status", "repo", nil}, | ||
{"repo,public_repo", "repo", nil}, | ||
{"admin:public_key,write:public_key", "admin:public_key", nil}, | ||
{"admin:public_key,read:public_key", "admin:public_key", nil}, | ||
{"write:public_key,read:public_key", "write:public_key", nil}, // read is include in write | ||
{"admin:repo_hook,write:repo_hook", "admin:repo_hook", nil}, | ||
{"admin:repo_hook,read:repo_hook", "admin:repo_hook", nil}, | ||
{"repo,admin:repo_hook,read:repo_hook", "repo", nil}, // admin:repo_hook is a child scope of repo | ||
{"repo,read:repo_hook", "repo", nil}, // read:repo_hook is a child scope of repo | ||
{"user", "user", nil}, | ||
{"user,read:user", "user", nil}, | ||
{"user,admin:org,write:org", "admin:org,user", nil}, | ||
{"admin:org,write:org,user", "admin:org,user", nil}, | ||
{"package", "package", nil}, | ||
{"package,write:package", "package", nil}, | ||
{"package,write:package,delete:package", "package", nil}, | ||
{"write:package,read:package", "write:package", nil}, // read is include in write | ||
{"write:package,delete:package", "write:package,delete:package", nil}, // write and delete are not include in each other | ||
{"admin:gpg_key", "admin:gpg_key", nil}, | ||
{"admin:gpg_key,write:gpg_key", "admin:gpg_key", nil}, | ||
{"admin:gpg_key,write:gpg_key,user", "user,admin:gpg_key", nil}, | ||
{"admin:application,write:application,user", "user,admin:application", nil}, | ||
{"all", "all", nil}, | ||
{"repo,admin:org,admin:public_key,admin:repo_hook,admin:org_hook,notification,user,delete_repo,package,admin:gpg_key,admin:application", "all", nil}, | ||
{"repo,admin:org,admin:public_key,admin:repo_hook,admin:org_hook,notification,user,delete_repo,package,admin:gpg_key,admin:application,sudo", "all,sudo", nil}, | ||
} | ||
|
||
for _, test := range tests { | ||
t.Run(string(test.in), func(t *testing.T) { | ||
scope, err := test.in.Normalize() | ||
assert.Equal(t, test.out, scope) | ||
assert.Equal(t, test.err, err) | ||
}) | ||
} | ||
} | ||
|
||
func TestAccessTokenScope_HasScope(t *testing.T) { | ||
tests := []struct { | ||
in AccessTokenScope | ||
scope AccessTokenScope | ||
out bool | ||
err error | ||
}{ | ||
{"repo", "repo", true, nil}, | ||
{"repo", "repo:status", true, nil}, | ||
{"repo", "public_repo", true, nil}, | ||
{"repo", "admin:org", false, nil}, | ||
{"repo", "admin:public_key", false, nil}, | ||
{"repo:status", "repo", false, nil}, | ||
{"repo:status", "public_repo", false, nil}, | ||
{"admin:org", "write:org", true, nil}, | ||
{"admin:org", "read:org", true, nil}, | ||
{"admin:org", "admin:org", true, nil}, | ||
{"user", "read:user", true, nil}, | ||
{"package", "write:package", true, nil}, | ||
} | ||
|
||
for _, test := range tests { | ||
t.Run(string(test.in), func(t *testing.T) { | ||
scope, err := test.in.HasScope(test.scope) | ||
assert.Equal(t, test.out, scope) | ||
assert.Equal(t, test.err, err) | ||
}) | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.