Access control: allow using targetOrgId parameter to set organization ID for a request (#41761)

* read target org ID in context handler

* simplify test

* add test for request body not being read in ctx handler

* linting fix
This commit is contained in:
Ieva 2021-11-17 15:11:56 +00:00 committed by GitHub
parent d623285fcc
commit c426f5673b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 68 additions and 0 deletions

View File

@ -4,10 +4,12 @@ import (
"context"
"errors"
"fmt"
"io"
"net"
"net/http"
"path/filepath"
"strconv"
"strings"
"testing"
"time"
@ -497,6 +499,58 @@ func TestMiddlewareContext(t *testing.T) {
cfg.AuthProxyAutoSignUp = true
})
middlewareScenario(t, "Should use organisation specified by targetOrgId parameter", func(t *testing.T, sc *scenarioContext) {
bus.AddHandlerCtx("test", func(ctx context.Context, query *models.GetSignedInUserQuery) error {
if query.UserId > 0 {
query.Result = &models.SignedInUser{OrgId: query.OrgId, UserId: userID}
return nil
}
return models.ErrUserNotFound
})
bus.AddHandler("test", func(cmd *models.UpsertUserCommand) error {
cmd.Result = &models.User{Id: userID}
return nil
})
targetOrgID := 123
sc.fakeReq("GET", fmt.Sprintf("/?targetOrgId=%d", targetOrgID))
sc.req.Header.Set(sc.cfg.AuthProxyHeaderName, hdrName)
sc.exec()
assert.True(t, sc.context.IsSignedIn)
assert.Equal(t, userID, sc.context.UserId)
assert.Equal(t, int64(targetOrgID), sc.context.OrgId)
}, func(cfg *setting.Cfg) {
configure(cfg)
cfg.LDAPEnabled = false
cfg.AuthProxyAutoSignUp = true
})
middlewareScenario(t, "Request body should not be read in default context handler", func(t *testing.T, sc *scenarioContext) {
sc.fakeReq("POST", "/?targetOrgId=123")
body := "key=value"
sc.req.Body = io.NopCloser(strings.NewReader(body))
sc.handlerFunc = func(c *models.ReqContext) {
t.Log("Handler called")
defer func() {
err := c.Req.Body.Close()
require.NoError(t, err)
}()
bodyAfterHandler, e := io.ReadAll(c.Req.Body)
require.NoError(t, e)
require.Equal(t, body, string(bodyAfterHandler))
}
sc.req.Header.Set(sc.cfg.AuthProxyHeaderName, hdrName)
sc.req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
sc.req.Header.Set("Content-Length", strconv.Itoa(len(body)))
sc.m.Post("/", sc.defaultHandler)
sc.exec()
})
middlewareScenario(t, "Should get an existing user from header", func(t *testing.T, sc *scenarioContext) {
const userID int64 = 12
const orgID int64 = 2

View File

@ -4,6 +4,7 @@ package contexthandler
import (
"context"
"errors"
"net/url"
"strconv"
"strings"
"time"
@ -105,6 +106,19 @@ func (h *ContextHandler) Middleware(mContext *web.Context) {
}
}
queryParameters, err := url.ParseQuery(reqContext.Req.URL.RawQuery)
if err != nil {
reqContext.Logger.Error("Failed to parse query parameters", "error", err)
}
if queryParameters.Has("targetOrgId") {
targetOrg, err := strconv.ParseInt(queryParameters.Get("targetOrgId"), 10, 64)
if err == nil {
orgID = targetOrg
} else {
reqContext.Logger.Error("Invalid target organization ID", "error", err)
}
}
// the order in which these are tested are important
// look for api key in Authorization header first
// then init session and look for userId in session