forked from NYANDEV/forgejo
Fix token endpoints ignore specified account (#27080)
Fix #26234 close #26323 close #27040 --------- Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
parent
8531ca0837
commit
f93ee5937b
4 changed files with 52 additions and 4 deletions
|
@ -367,6 +367,16 @@ func reqOwner() func(ctx *context.APIContext) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reqSelfOrAdmin doer should be the same as the contextUser or site admin
|
||||||
|
func reqSelfOrAdmin() func(ctx *context.APIContext) {
|
||||||
|
return func(ctx *context.APIContext) {
|
||||||
|
if !ctx.IsUserSiteAdmin() && ctx.ContextUser != ctx.Doer {
|
||||||
|
ctx.Error(http.StatusForbidden, "reqSelfOrAdmin", "doer should be the site admin or be same as the contextUser")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// reqAdmin user should be an owner or a collaborator with admin write of a repository, or site admin
|
// reqAdmin user should be an owner or a collaborator with admin write of a repository, or site admin
|
||||||
func reqAdmin() func(ctx *context.APIContext) {
|
func reqAdmin() func(ctx *context.APIContext) {
|
||||||
return func(ctx *context.APIContext) {
|
return func(ctx *context.APIContext) {
|
||||||
|
@ -910,7 +920,7 @@ func Routes() *web.Route {
|
||||||
m.Combo("").Get(user.ListAccessTokens).
|
m.Combo("").Get(user.ListAccessTokens).
|
||||||
Post(bind(api.CreateAccessTokenOption{}), reqToken(), user.CreateAccessToken)
|
Post(bind(api.CreateAccessTokenOption{}), reqToken(), user.CreateAccessToken)
|
||||||
m.Combo("/{id}").Delete(reqToken(), user.DeleteAccessToken)
|
m.Combo("/{id}").Delete(reqToken(), user.DeleteAccessToken)
|
||||||
}, reqBasicOrRevProxyAuth())
|
}, reqSelfOrAdmin(), reqBasicOrRevProxyAuth())
|
||||||
|
|
||||||
m.Get("/activities/feeds", user.ListUserActivityFeeds)
|
m.Get("/activities/feeds", user.ListUserActivityFeeds)
|
||||||
}, context_service.UserAssignmentAPI())
|
}, context_service.UserAssignmentAPI())
|
||||||
|
|
|
@ -43,8 +43,10 @@ func ListAccessTokens(ctx *context.APIContext) {
|
||||||
// responses:
|
// responses:
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/AccessTokenList"
|
// "$ref": "#/responses/AccessTokenList"
|
||||||
|
// "403":
|
||||||
|
// "$ref": "#/responses/forbidden"
|
||||||
|
|
||||||
opts := auth_model.ListAccessTokensOptions{UserID: ctx.Doer.ID, ListOptions: utils.GetListOptions(ctx)}
|
opts := auth_model.ListAccessTokensOptions{UserID: ctx.ContextUser.ID, ListOptions: utils.GetListOptions(ctx)}
|
||||||
|
|
||||||
count, err := auth_model.CountAccessTokens(ctx, opts)
|
count, err := auth_model.CountAccessTokens(ctx, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -95,11 +97,13 @@ func CreateAccessToken(ctx *context.APIContext) {
|
||||||
// "$ref": "#/responses/AccessToken"
|
// "$ref": "#/responses/AccessToken"
|
||||||
// "400":
|
// "400":
|
||||||
// "$ref": "#/responses/error"
|
// "$ref": "#/responses/error"
|
||||||
|
// "403":
|
||||||
|
// "$ref": "#/responses/forbidden"
|
||||||
|
|
||||||
form := web.GetForm(ctx).(*api.CreateAccessTokenOption)
|
form := web.GetForm(ctx).(*api.CreateAccessTokenOption)
|
||||||
|
|
||||||
t := &auth_model.AccessToken{
|
t := &auth_model.AccessToken{
|
||||||
UID: ctx.Doer.ID,
|
UID: ctx.ContextUser.ID,
|
||||||
Name: form.Name,
|
Name: form.Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,6 +157,8 @@ func DeleteAccessToken(ctx *context.APIContext) {
|
||||||
// responses:
|
// responses:
|
||||||
// "204":
|
// "204":
|
||||||
// "$ref": "#/responses/empty"
|
// "$ref": "#/responses/empty"
|
||||||
|
// "403":
|
||||||
|
// "$ref": "#/responses/forbidden"
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
// "422":
|
// "422":
|
||||||
|
@ -164,7 +170,7 @@ func DeleteAccessToken(ctx *context.APIContext) {
|
||||||
if tokenID == 0 {
|
if tokenID == 0 {
|
||||||
tokens, err := auth_model.ListAccessTokens(ctx, auth_model.ListAccessTokensOptions{
|
tokens, err := auth_model.ListAccessTokens(ctx, auth_model.ListAccessTokensOptions{
|
||||||
Name: token,
|
Name: token,
|
||||||
UserID: ctx.Doer.ID,
|
UserID: ctx.ContextUser.ID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "ListAccessTokens", err)
|
ctx.Error(http.StatusInternalServerError, "ListAccessTokens", err)
|
||||||
|
|
9
templates/swagger/v1_json.tmpl
generated
9
templates/swagger/v1_json.tmpl
generated
|
@ -16359,6 +16359,9 @@
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"$ref": "#/responses/AccessTokenList"
|
"$ref": "#/responses/AccessTokenList"
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"$ref": "#/responses/forbidden"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -16396,6 +16399,9 @@
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
"$ref": "#/responses/error"
|
"$ref": "#/responses/error"
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"$ref": "#/responses/forbidden"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16430,6 +16436,9 @@
|
||||||
"204": {
|
"204": {
|
||||||
"$ref": "#/responses/empty"
|
"$ref": "#/responses/empty"
|
||||||
},
|
},
|
||||||
|
"403": {
|
||||||
|
"$ref": "#/responses/forbidden"
|
||||||
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"$ref": "#/responses/notFound"
|
"$ref": "#/responses/notFound"
|
||||||
},
|
},
|
||||||
|
|
|
@ -40,6 +40,29 @@ func TestAPIDeleteMissingToken(t *testing.T) {
|
||||||
MakeRequest(t, req, http.StatusNotFound)
|
MakeRequest(t, req, http.StatusNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestAPIGetTokensPermission ensures that only the admin can get tokens from other users
|
||||||
|
func TestAPIGetTokensPermission(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
// admin can get tokens for other users
|
||||||
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||||
|
req := NewRequestf(t, "GET", "/api/v1/users/user2/tokens")
|
||||||
|
req = AddBasicAuthHeader(req, user.Name)
|
||||||
|
MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
// non-admin can get tokens for himself
|
||||||
|
user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
|
req = NewRequestf(t, "GET", "/api/v1/users/user2/tokens")
|
||||||
|
req = AddBasicAuthHeader(req, user.Name)
|
||||||
|
MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
// non-admin can't get tokens for other users
|
||||||
|
user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
|
||||||
|
req = NewRequestf(t, "GET", "/api/v1/users/user2/tokens")
|
||||||
|
req = AddBasicAuthHeader(req, user.Name)
|
||||||
|
MakeRequest(t, req, http.StatusForbidden)
|
||||||
|
}
|
||||||
|
|
||||||
type permission struct {
|
type permission struct {
|
||||||
category auth_model.AccessTokenScopeCategory
|
category auth_model.AccessTokenScopeCategory
|
||||||
level auth_model.AccessTokenScopeLevel
|
level auth_model.AccessTokenScopeLevel
|
||||||
|
|
Loading…
Reference in a new issue