Add sudo functionality to the API (#4809)

tokarchuk/v1.17
zeripath 6 years ago committed by techknowlogick
parent e6a03813d4
commit d293a2b9d6
  1. 4
      docs/content/doc/advanced/api-usage.en-us.md
  2. 29
      integrations/api_admin_test.go
  3. 45
      routers/api/v1/api.go
  4. 18
      templates/swagger/v1_json.tmpl

@ -73,3 +73,7 @@ using BasicAuth, as follows:
$ curl --request GET --url https://yourusername:yourpassword@gitea.your.host/api/v1/users/yourusername/tokens $ curl --request GET --url https://yourusername:yourpassword@gitea.your.host/api/v1/users/yourusername/tokens
[{"name":"test","sha1":"..."},{"name":"dev","sha1":"..."}] [{"name":"test","sha1":"..."},{"name":"dev","sha1":"..."}]
``` ```
## Sudo
The API allows admin users to sudo API requests as another user. Simply add either a `sudo=` parameter or `Sudo:` request header with the username of the user to sudo.

@ -9,6 +9,8 @@ import (
"net/http" "net/http"
"testing" "testing"
"github.com/stretchr/testify/assert"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
api "code.gitea.io/sdk/gitea" api "code.gitea.io/sdk/gitea"
) )
@ -71,3 +73,30 @@ func TestAPIAdminDeleteUnauthorizedKey(t *testing.T) {
adminUsername, newPublicKey.ID) adminUsername, newPublicKey.ID)
session.MakeRequest(t, req, http.StatusForbidden) session.MakeRequest(t, req, http.StatusForbidden)
} }
func TestAPISudoUser(t *testing.T) {
prepareTestEnv(t)
adminUsername := "user1"
normalUsername := "user2"
session := loginUser(t, adminUsername)
urlStr := fmt.Sprintf("/api/v1/user?sudo=%s", normalUsername)
req := NewRequest(t, "GET", urlStr)
resp := session.MakeRequest(t, req, http.StatusOK)
var user api.User
DecodeJSON(t, resp, &user)
assert.Equal(t, normalUsername, user.UserName)
}
func TestAPISudoUserForbidden(t *testing.T) {
prepareTestEnv(t)
adminUsername := "user1"
normalUsername := "user2"
session := loginUser(t, normalUsername)
urlStr := fmt.Sprintf("/api/v1/user?sudo=%s", adminUsername)
req := NewRequest(t, "GET", urlStr)
session.MakeRequest(t, req, http.StatusForbidden)
}

@ -24,6 +24,8 @@
// - Token : // - Token :
// - AccessToken : // - AccessToken :
// - AuthorizationHeaderToken : // - AuthorizationHeaderToken :
// - SudoParam :
// - SudoHeader :
// //
// SecurityDefinitions: // SecurityDefinitions:
// BasicAuth: // BasicAuth:
@ -40,6 +42,16 @@
// type: apiKey // type: apiKey
// name: Authorization // name: Authorization
// in: header // in: header
// SudoParam:
// type: apiKey
// name: sudo
// in: query
// description: Sudo API request as the user provided as the key. Admin privileges are required.
// SudoHeader:
// type: apiKey
// name: Sudo
// in: header
// description: Sudo API request as the user provided as the key. Admin privileges are required.
// //
// swagger:meta // swagger:meta
package v1 package v1
@ -50,6 +62,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers/api/v1/admin" "code.gitea.io/gitea/routers/api/v1/admin"
"code.gitea.io/gitea/routers/api/v1/misc" "code.gitea.io/gitea/routers/api/v1/misc"
@ -64,6 +77,36 @@ import (
"gopkg.in/macaron.v1" "gopkg.in/macaron.v1"
) )
func sudo() macaron.Handler {
return func(ctx *context.APIContext) {
sudo := ctx.Query("sudo")
if len(sudo) <= 0 {
sudo = ctx.Req.Header.Get("Sudo")
}
if len(sudo) > 0 {
if ctx.User.IsAdmin {
user, err := models.GetUserByName(sudo)
if err != nil {
if models.IsErrUserNotExist(err) {
ctx.Status(404)
} else {
ctx.Error(500, "GetUserByName", err)
}
return
}
log.Trace("Sudo from (%s) to: %s", ctx.User.Name, user.Name)
ctx.User = user
} else {
ctx.JSON(403, map[string]string{
"message": "Only administrators allowed to sudo.",
})
return
}
}
}
}
func repoAssignment() macaron.Handler { func repoAssignment() macaron.Handler {
return func(ctx *context.APIContext) { return func(ctx *context.APIContext) {
userName := ctx.Params(":username") userName := ctx.Params(":username")
@ -589,5 +632,5 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/topics", func() { m.Group("/topics", func() {
m.Get("/search", repo.TopicSearch) m.Get("/search", repo.TopicSearch)
}) })
}, context.APIContexter()) }, context.APIContexter(), sudo())
} }

@ -8008,6 +8008,18 @@
"BasicAuth": { "BasicAuth": {
"type": "basic" "type": "basic"
}, },
"SudoHeader": {
"description": "Sudo API request as the user provided as the key. Admin privileges are required.",
"type": "apiKey",
"name": "Sudo",
"in": "header"
},
"SudoParam": {
"description": "Sudo API request as the user provided as the key. Admin privileges are required.",
"type": "apiKey",
"name": "sudo",
"in": "query"
},
"Token": { "Token": {
"type": "apiKey", "type": "apiKey",
"name": "token", "name": "token",
@ -8026,6 +8038,12 @@
}, },
{ {
"AuthorizationHeaderToken": [] "AuthorizationHeaderToken": []
},
{
"SudoParam": []
},
{
"SudoHeader": []
} }
] ]
} }
Loading…
Cancel
Save