| @@ -73,3 +73,7 @@ using BasicAuth, as follows: | |||
| $ curl --request GET --url https://yourusername:yourpassword@gitea.your.host/api/v1/users/yourusername/tokens | |||
| [{"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" | |||
| "testing" | |||
| "github.com/stretchr/testify/assert" | |||
| "code.gitea.io/gitea/models" | |||
| api "code.gitea.io/sdk/gitea" | |||
| ) | |||
| @@ -71,3 +73,30 @@ func TestAPIAdminDeleteUnauthorizedKey(t *testing.T) { | |||
| adminUsername, newPublicKey.ID) | |||
| 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 : | |||
| // - AccessToken : | |||
| // - AuthorizationHeaderToken : | |||
| // - SudoParam : | |||
| // - SudoHeader : | |||
| // | |||
| // SecurityDefinitions: | |||
| // BasicAuth: | |||
| @@ -40,6 +42,16 @@ | |||
| // type: apiKey | |||
| // name: Authorization | |||
| // 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 | |||
| package v1 | |||
| @@ -50,6 +62,7 @@ import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/auth" | |||
| "code.gitea.io/gitea/modules/context" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "code.gitea.io/gitea/routers/api/v1/admin" | |||
| "code.gitea.io/gitea/routers/api/v1/misc" | |||
| @@ -64,6 +77,36 @@ import ( | |||
| "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 { | |||
| return func(ctx *context.APIContext) { | |||
| userName := ctx.Params(":username") | |||
| @@ -589,5 +632,5 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Group("/topics", func() { | |||
| m.Get("/search", repo.TopicSearch) | |||
| }) | |||
| }, context.APIContexter()) | |||
| }, context.APIContexter(), sudo()) | |||
| } | |||
| @@ -8008,6 +8008,18 @@ | |||
| "BasicAuth": { | |||
| "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": { | |||
| "type": "apiKey", | |||
| "name": "token", | |||
| @@ -8026,6 +8038,12 @@ | |||
| }, | |||
| { | |||
| "AuthorizationHeaderToken": [] | |||
| }, | |||
| { | |||
| "SudoParam": [] | |||
| }, | |||
| { | |||
| "SudoHeader": [] | |||
| } | |||
| ] | |||
| } | |||