@@ -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": [] | |||
} | |||
] | |||
} |