mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 13:51:35 +01:00 
			
		
		
		
	Add sudo functionality to the API (#4809)
This commit is contained in:
		
							parent
							
								
									e6a03813d4
								
							
						
					
					
						commit
						d293a2b9d6
					
				| @ -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": [] | ||||
|     } | ||||
|   ] | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user