Skip to content

Commit f93ee59

Browse files
Fix token endpoints ignore specified account (#27080)
Fix #26234 close #26323 close #27040 --------- Co-authored-by: silverwind <me@silverwind.io>
1 parent 8531ca0 commit f93ee59

File tree

4 files changed

+52
-4
lines changed

4 files changed

+52
-4
lines changed

routers/api/v1/api.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,16 @@ func reqOwner() func(ctx *context.APIContext) {
367367
}
368368
}
369369

370+
// reqSelfOrAdmin doer should be the same as the contextUser or site admin
371+
func reqSelfOrAdmin() func(ctx *context.APIContext) {
372+
return func(ctx *context.APIContext) {
373+
if !ctx.IsUserSiteAdmin() && ctx.ContextUser != ctx.Doer {
374+
ctx.Error(http.StatusForbidden, "reqSelfOrAdmin", "doer should be the site admin or be same as the contextUser")
375+
return
376+
}
377+
}
378+
}
379+
370380
// reqAdmin user should be an owner or a collaborator with admin write of a repository, or site admin
371381
func reqAdmin() func(ctx *context.APIContext) {
372382
return func(ctx *context.APIContext) {
@@ -910,7 +920,7 @@ func Routes() *web.Route {
910920
m.Combo("").Get(user.ListAccessTokens).
911921
Post(bind(api.CreateAccessTokenOption{}), reqToken(), user.CreateAccessToken)
912922
m.Combo("/{id}").Delete(reqToken(), user.DeleteAccessToken)
913-
}, reqBasicOrRevProxyAuth())
923+
}, reqSelfOrAdmin(), reqBasicOrRevProxyAuth())
914924

915925
m.Get("/activities/feeds", user.ListUserActivityFeeds)
916926
}, context_service.UserAssignmentAPI())

routers/api/v1/user/app.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@ func ListAccessTokens(ctx *context.APIContext) {
4343
// responses:
4444
// "200":
4545
// "$ref": "#/responses/AccessTokenList"
46+
// "403":
47+
// "$ref": "#/responses/forbidden"
4648

47-
opts := auth_model.ListAccessTokensOptions{UserID: ctx.Doer.ID, ListOptions: utils.GetListOptions(ctx)}
49+
opts := auth_model.ListAccessTokensOptions{UserID: ctx.ContextUser.ID, ListOptions: utils.GetListOptions(ctx)}
4850

4951
count, err := auth_model.CountAccessTokens(ctx, opts)
5052
if err != nil {
@@ -95,11 +97,13 @@ func CreateAccessToken(ctx *context.APIContext) {
9597
// "$ref": "#/responses/AccessToken"
9698
// "400":
9799
// "$ref": "#/responses/error"
100+
// "403":
101+
// "$ref": "#/responses/forbidden"
98102

99103
form := web.GetForm(ctx).(*api.CreateAccessTokenOption)
100104

101105
t := &auth_model.AccessToken{
102-
UID: ctx.Doer.ID,
106+
UID: ctx.ContextUser.ID,
103107
Name: form.Name,
104108
}
105109

@@ -153,6 +157,8 @@ func DeleteAccessToken(ctx *context.APIContext) {
153157
// responses:
154158
// "204":
155159
// "$ref": "#/responses/empty"
160+
// "403":
161+
// "$ref": "#/responses/forbidden"
156162
// "404":
157163
// "$ref": "#/responses/notFound"
158164
// "422":
@@ -164,7 +170,7 @@ func DeleteAccessToken(ctx *context.APIContext) {
164170
if tokenID == 0 {
165171
tokens, err := auth_model.ListAccessTokens(ctx, auth_model.ListAccessTokensOptions{
166172
Name: token,
167-
UserID: ctx.Doer.ID,
173+
UserID: ctx.ContextUser.ID,
168174
})
169175
if err != nil {
170176
ctx.Error(http.StatusInternalServerError, "ListAccessTokens", err)

templates/swagger/v1_json.tmpl

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/integration/api_token_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,29 @@ func TestAPIDeleteMissingToken(t *testing.T) {
4040
MakeRequest(t, req, http.StatusNotFound)
4141
}
4242

43+
// TestAPIGetTokensPermission ensures that only the admin can get tokens from other users
44+
func TestAPIGetTokensPermission(t *testing.T) {
45+
defer tests.PrepareTestEnv(t)()
46+
47+
// admin can get tokens for other users
48+
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
49+
req := NewRequestf(t, "GET", "/api/v1/users/user2/tokens")
50+
req = AddBasicAuthHeader(req, user.Name)
51+
MakeRequest(t, req, http.StatusOK)
52+
53+
// non-admin can get tokens for himself
54+
user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
55+
req = NewRequestf(t, "GET", "/api/v1/users/user2/tokens")
56+
req = AddBasicAuthHeader(req, user.Name)
57+
MakeRequest(t, req, http.StatusOK)
58+
59+
// non-admin can't get tokens for other users
60+
user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
61+
req = NewRequestf(t, "GET", "/api/v1/users/user2/tokens")
62+
req = AddBasicAuthHeader(req, user.Name)
63+
MakeRequest(t, req, http.StatusForbidden)
64+
}
65+
4366
type permission struct {
4467
category auth_model.AccessTokenScopeCategory
4568
level auth_model.AccessTokenScopeLevel

0 commit comments

Comments
 (0)