Skip to content

Commit

Permalink
Redesign Scoped Access Tokens (#24767)
Browse files Browse the repository at this point in the history
## Changes
- Adds the following high level access scopes, each with `read` and
`write` levels:
    - `activitypub`
    - `admin` (hidden if user is not a site admin)
    - `misc`
    - `notification`
    - `organization`
    - `package`
    - `issue`
    - `repository`
    - `user`
- Adds new middleware function `tokenRequiresScopes()` in addition to
`reqToken()`
  -  `tokenRequiresScopes()` is used for each high-level api section
- _if_ a scoped token is present, checks that the required scope is
included based on the section and HTTP method
  - `reqToken()` is used for individual routes
- checks that required authentication is present (but does not check
scope levels as this will already have been handled by
`tokenRequiresScopes()`
- Adds migration to convert old scoped access tokens to the new set of
scopes
- Updates the user interface for scope selection

### User interface example
<img width="903" alt="Screen Shot 2023-05-31 at 1 56 55 PM"
src="https://github.com/go-gitea/gitea/assets/23248839/654766ec-2143-4f59-9037-3b51600e32f3">
<img width="917" alt="Screen Shot 2023-05-31 at 1 56 43 PM"
src="https://github.com/go-gitea/gitea/assets/23248839/1ad64081-012c-4a73-b393-66b30352654c">

## tokenRequiresScopes  Design Decision
- `tokenRequiresScopes()` was added to more reliably cover api routes.
For an incoming request, this function uses the given scope category
(say `AccessTokenScopeCategoryOrganization`) and the HTTP method (say
`DELETE`) and verifies that any scoped tokens in use include
`delete:organization`.
- `reqToken()` is used to enforce auth for individual routes that
require it. If a scoped token is not present for a request,
`tokenRequiresScopes()` will not return an error

## TODO
- [x] Alphabetize scope categories
- [x] Change 'public repos only' to a radio button (private vs public).
Also expand this to organizations
- [X] Disable token creation if no scopes selected. Alternatively, show
warning
- [x] `reqToken()` is missing from many `POST/DELETE` routes in the api.
`tokenRequiresScopes()` only checks that a given token has the correct
scope, `reqToken()` must be used to check that a token (or some other
auth) is present.
   -  _This should be addressed in this PR_
- [x] The migration should be reviewed very carefully in order to
minimize access changes to existing user tokens.
   - _This should be addressed in this PR_
- [x] Link to api to swagger documentation, clarify what
read/write/delete levels correspond to
- [x] Review cases where more than one scope is needed as this directly
deviates from the api definition.
   - _This should be addressed in this PR_
   - For example: 
   ```go
	m.Group("/users/{username}/orgs", func() {
		m.Get("", reqToken(), org.ListUserOrgs)
		m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions)
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser,
auth_model.AccessTokenScopeCategoryOrganization),
context_service.UserAssignmentAPI())
   ```

## Future improvements
- [ ] Add required scopes to swagger documentation
- [ ] Redesign `reqToken()` to be opt-out rather than opt-in
- [ ] Subdivide scopes like `repository`
- [ ] Once a token is created, if it has no scopes, we should display
text instead of an empty bullet point
- [ ] If the 'public repos only' option is selected, should read
categories be selected by default

Closes #24501
Closes #24799

Co-authored-by: Jonathan Tran <jon@allspice.io>
Co-authored-by: Kyle D <kdumontnu@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
  • Loading branch information
4 people authored Jun 4, 2023
1 parent 520eb57 commit 18de83b
Show file tree
Hide file tree
Showing 102 changed files with 2,182 additions and 1,037 deletions.
73 changes: 37 additions & 36 deletions docs/content/doc/development/oauth2-provider.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,42 +44,43 @@ To use the Authorization Code Grant as a third party application it is required

## Scopes

Gitea supports the following scopes for tokens:

| Name | Description |
| ---- | ----------- |
| **(no scope)** | Grants read-only access to public user profile and public repositories. |
| **repo** | Full control over all repositories. |
| &nbsp;&nbsp;&nbsp; **repo:status** | Grants read/write access to commit status in all repositories. |
| &nbsp;&nbsp;&nbsp; **public_repo** | Grants read/write access to public repositories only. |
| **admin:repo_hook** | Grants access to repository hooks of all repositories. This is included in the `repo` scope. |
| &nbsp;&nbsp;&nbsp; **write:repo_hook** | Grants read/write access to repository hooks |
| &nbsp;&nbsp;&nbsp; **read:repo_hook** | Grants read-only access to repository hooks |
| **admin:org** | Grants full access to organization settings |
| &nbsp;&nbsp;&nbsp; **write:org** | Grants read/write access to organization settings |
| &nbsp;&nbsp;&nbsp; **read:org** | Grants read-only access to organization settings |
| **admin:public_key** | Grants full access for managing public keys |
| &nbsp;&nbsp;&nbsp; **write:public_key** | Grant read/write access to public keys |
| &nbsp;&nbsp;&nbsp; **read:public_key** | Grant read-only access to public keys |
| **admin:org_hook** | Grants full access to organizational-level hooks |
| **admin:user_hook** | Grants full access to user-level hooks |
| **notification** | Grants full access to notifications |
| **user** | Grants full access to user profile info |
| &nbsp;&nbsp;&nbsp; **read:user** | Grants read access to user's profile |
| &nbsp;&nbsp;&nbsp; **user:email** | Grants read access to user's email addresses |
| &nbsp;&nbsp;&nbsp; **user:follow** | Grants access to follow/un-follow a user |
| **delete_repo** | Grants access to delete repositories as an admin |
| **package** | Grants full access to hosted packages |
| &nbsp;&nbsp;&nbsp; **write:package** | Grants read/write access to packages |
| &nbsp;&nbsp;&nbsp; **read:package** | Grants read access to packages |
| &nbsp;&nbsp;&nbsp; **delete:package** | Grants delete access to packages |
| **admin:gpg_key** | Grants full access for managing GPG keys |
| &nbsp;&nbsp;&nbsp; **write:gpg_key** | Grants read/write access to GPG keys |
| &nbsp;&nbsp;&nbsp; **read:gpg_key** | Grants read-only access to GPG keys |
| **admin:application** | Grants full access to manage applications |
| &nbsp;&nbsp;&nbsp; **write:application** | Grants read/write access for managing applications |
| &nbsp;&nbsp;&nbsp; **read:application** | Grants read access for managing applications |
| **sudo** | Allows to perform actions as the site admin. |
Gitea supports scoped access tokens, which allow users the ability to restrict tokens to operate only on selected url routes. Scopes are grouped by high-level API routes, and further refined to the following:

- `read`: `GET` routes
- `write`: `POST`, `PUT`, `PATCH`, and `DELETE` routes (in addition to `GET`)

Gitea token scopes are as follows:

| Name | Description |
| ---- |--------------------------------------------------------------------------------------------------------------------------------------------------|
| **(no scope)** | Not supported. A scope is required even for public repositories. |
| **activitypub** | `activitypub` API routes: ActivityPub related operations. |
| &nbsp;&nbsp;&nbsp; **read:activitypub** | Grants read access for ActivityPub operations. |
| &nbsp;&nbsp;&nbsp; **write:activitypub** | Grants read/write/delete access for ActivityPub operations. |
| **admin** | `/admin/*` API routes: Site-wide administrative operations (hidden for non-admin accounts). |
| &nbsp;&nbsp;&nbsp; **read:admin** | Grants read access for admin operations, such as getting cron jobs or registered user emails. |
| &nbsp;&nbsp;&nbsp; **write:admin** | Grants read/write/delete access for admin operations, such as running cron jobs or updating user accounts. | |
| **issue** | `issues/*`, `labels/*`, `milestones/*` API routes: Issue-related operations. |
| &nbsp;&nbsp;&nbsp; **read:issue** | Grants read access for issues operations, such as getting issue comments, issue attachments, and milestones. |
| &nbsp;&nbsp;&nbsp; **write:issue** | Grants read/write/delete access for issues operations, such as posting or editing an issue comment or attachment, and updating milestones. |
| **misc** | miscellaneous and settings top-level API routes. |
| &nbsp;&nbsp;&nbsp; **read:misc** | Grants read access to miscellaneous operations, such as getting label and gitignore templates. |
| &nbsp;&nbsp;&nbsp; **write:misc** | Grants read/write/delete access to miscellaneous operations, such as markup utility operations. |
| **notification** | `notification/*` API routes: user notification operations. |
| &nbsp;&nbsp;&nbsp; **read:notification** | Grants read access to user notifications, such as which notifications users are subscribed to and read new notifications. |
| &nbsp;&nbsp;&nbsp; **write:notification** | Grants read/write/delete access to user notifications, such as marking notifications as read. |
| **organization** | `orgs/*` and `teams/*` API routes: Organization and team management operations. |
| &nbsp;&nbsp;&nbsp; **read:organization** | Grants read access to org and team status, such as listing all orgs a user has visibility to, teams, and team members. |
| &nbsp;&nbsp;&nbsp; **write:organization** | Grants read/write/delete access to org and team status, such as creating and updating teams and updating org settings. |
| **package** | `/packages/*` API routes: Packages operations |
| &nbsp;&nbsp;&nbsp; **read:package** | Grants read access to package operations, such as reading and downloading available packages. |
| &nbsp;&nbsp;&nbsp; **write:package** | Grants read/write/delete access to package operations. Currently the same as `read:package`. |
| **repository** | `/repos/*` API routes except `/repos/issues/*`: Repository file, pull-request, and release operations. |
| &nbsp;&nbsp;&nbsp; **read:repository** | Grants read access to repository operations, such as getting repository files, releases, collaborators. |
| &nbsp;&nbsp;&nbsp; **write:repository** | Grants read/write/delete access to repository operations, such as getting updating repository files, creating pull requests, updating collaborators. |
| **user** | `/user/*` and `/users/*` API routes: User-related operations. |
| &nbsp;&nbsp;&nbsp; **read:user** | Grants read access to user operations, such as getting user repo subscriptions and user settings. |
| &nbsp;&nbsp;&nbsp; **write:user** | Grants read/write/delete access to user operations, such as updating user repo subscriptions, followed users, and user settings. |

## Client types

Expand Down
9 changes: 9 additions & 0 deletions models/auth/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,15 @@ func NewAccessToken(t *AccessToken) error {
return err
}

// DisplayPublicOnly whether to display this as a public-only token.
func (t *AccessToken) DisplayPublicOnly() bool {
publicOnly, err := t.Scope.PublicOnly()
if err != nil {
return false
}
return publicOnly
}

func getAccessTokenIDFromCache(token string) int64 {
if successfulAccessTokenCache == nil {
return 0
Expand Down
Loading

0 comments on commit 18de83b

Please sign in to comment.