summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/content/doc/advanced/api-usage.en-us.md4
-rw-r--r--integrations/api_admin_test.go29
-rw-r--r--routers/api/v1/api.go45
-rw-r--r--templates/swagger/v1_json.tmpl18
4 files changed, 95 insertions, 1 deletions
diff --git a/docs/content/doc/advanced/api-usage.en-us.md b/docs/content/doc/advanced/api-usage.en-us.md
index f04a99f14b..369bae6cac 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/integrations/api_admin_test.go b/integrations/api_admin_test.go
index 37e5fd199a..ab878dd6a5 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)
+}
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index 47a8edab43..967db3b01c 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
@@ -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())
}
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index 598813bfc0..b4b65563dc 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