From 8ae3b1fbc70d48238c99a247cd3ac819180bb3c2 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Tue, 28 Aug 2018 12:22:26 +0100 Subject: [PATCH 1/4] Add sudo functionality Signed-off-by: Andrew Thornton --- routers/api/v1/api.go | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 47a8edab438fa..9ba6e8daaa74c 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -64,6 +64,35 @@ 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 + } + 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 +618,5 @@ func RegisterRoutes(m *macaron.Macaron) { m.Group("/topics", func() { m.Get("/search", repo.TopicSearch) }) - }, context.APIContexter()) + }, context.APIContexter(), sudo()) } From f8ebfd2a35aa8c3e1aacc32b34cef8f17de31198 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Tue, 28 Aug 2018 13:38:31 +0100 Subject: [PATCH 2/4] Add simple integration test for sudo Signed-off-by: Andrew Thornton --- integrations/api_admin_test.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/integrations/api_admin_test.go b/integrations/api_admin_test.go index 37e5fd199ad37..ab878dd6a56c8 100644 --- a/integrations/api_admin_test.go +++ b/integrations/api_admin_test.go @@ -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) +} From d24516450739123f48385473728f3437451d3b09 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Thu, 30 Aug 2018 10:31:59 +0100 Subject: [PATCH 3/4] Add documentation and information to the swagger api Signed-off-by: Andrew Thornton --- docs/content/doc/advanced/api-usage.en-us.md | 4 ++++ routers/api/v1/api.go | 12 ++++++++++++ templates/swagger/v1_json.tmpl | 18 ++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/docs/content/doc/advanced/api-usage.en-us.md b/docs/content/doc/advanced/api-usage.en-us.md index f04a99f14b123..369bae6cac8af 100644 --- a/docs/content/doc/advanced/api-usage.en-us.md +++ b/docs/content/doc/advanced/api-usage.en-us.md @@ -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. diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 9ba6e8daaa74c..bd670c8c0a593 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -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 diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 598813bfc0047..b4b65563dcf2d 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -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": [] } ] } \ No newline at end of file From af46b1b82d687c39d3a6f7cb09998c4f3c06237e Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Thu, 30 Aug 2018 11:24:30 +0100 Subject: [PATCH 4/4] Log that a sudo action has occurred Signed-off-by: Andrew Thornton --- routers/api/v1/api.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index bd670c8c0a593..967db3b01c4a3 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -62,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" @@ -94,6 +95,7 @@ func sudo() macaron.Handler { } return } + log.Trace("Sudo from (%s) to: %s", ctx.User.Name, user.Name) ctx.User = user } else { ctx.JSON(403, map[string]string{