AuthN: set org id for authentication request in service (#60528)
* AuthN: Replicate functionallity to get org id for request * Authn: parse org id for the request and populate the auth request with it * AuthN: add simple mock for client to use in test * AuthN: add tests to verify that authentication is called with correct org id * AuthN: Add ClientParams to mock * AuthN: Fix flaky org id selection
This commit is contained in:
@@ -2,6 +2,8 @@ package authnimpl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
@@ -15,6 +17,7 @@ import (
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
)
|
||||
|
||||
// make sure service implements authn.Service interface
|
||||
var _ authn.Service = new(Service)
|
||||
|
||||
func ProvideService(cfg *setting.Cfg, tracer tracing.Tracer, orgService org.Service, apikeyService apikey.Service, userService user.Service) *Service {
|
||||
@@ -24,7 +27,6 @@ func ProvideService(cfg *setting.Cfg, tracer tracing.Tracer, orgService org.Serv
|
||||
clients: make(map[string]authn.Client),
|
||||
tracer: tracer,
|
||||
postAuthHooks: []authn.PostAuthHookFn{},
|
||||
userService: userService,
|
||||
}
|
||||
|
||||
s.clients[authn.ClientAPIKey] = clients.ProvideAPIKey(apikeyService, userService)
|
||||
@@ -46,12 +48,9 @@ type Service struct {
|
||||
log log.Logger
|
||||
cfg *setting.Cfg
|
||||
clients map[string]authn.Client
|
||||
|
||||
// postAuthHooks are called after a successful authentication. They can modify the identity.
|
||||
postAuthHooks []authn.PostAuthHookFn
|
||||
|
||||
tracer tracing.Tracer
|
||||
userService user.Service
|
||||
tracer tracing.Tracer
|
||||
}
|
||||
|
||||
func (s *Service) Authenticate(ctx context.Context, client string, r *authn.Request) (*authn.Identity, bool, error) {
|
||||
@@ -74,6 +73,7 @@ func (s *Service) Authenticate(ctx context.Context, client string, r *authn.Requ
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
r.OrgID = orgIDFromRequest(r)
|
||||
identity, err := c.Authenticate(ctx, r)
|
||||
if err != nil {
|
||||
logger.Warn("auth client could not authenticate request", "client", client, "error", err)
|
||||
@@ -103,3 +103,46 @@ func (s *Service) Authenticate(ctx context.Context, client string, r *authn.Requ
|
||||
func (s *Service) RegisterPostAuthHook(hook authn.PostAuthHookFn) {
|
||||
s.postAuthHooks = append(s.postAuthHooks, hook)
|
||||
}
|
||||
|
||||
func orgIDFromRequest(r *authn.Request) int64 {
|
||||
if r.HTTPRequest == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
orgID := orgIDFromQuery(r.HTTPRequest)
|
||||
if orgID > 0 {
|
||||
return orgID
|
||||
}
|
||||
|
||||
return orgIDFromHeader(r.HTTPRequest)
|
||||
}
|
||||
|
||||
// name of query string used to target specific org for request
|
||||
const orgIDTargetQuery = "targetOrgId"
|
||||
|
||||
func orgIDFromQuery(req *http.Request) int64 {
|
||||
params := req.URL.Query()
|
||||
if !params.Has(orgIDTargetQuery) {
|
||||
return 0
|
||||
}
|
||||
id, err := strconv.ParseInt(params.Get(orgIDTargetQuery), 10, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// name of header containing org id for request
|
||||
const orgIDHeaderName = "X-Grafana-Org-Id"
|
||||
|
||||
func orgIDFromHeader(req *http.Request) int64 {
|
||||
header := req.Header.Get(orgIDHeaderName)
|
||||
if header == "" {
|
||||
return 0
|
||||
}
|
||||
id, err := strconv.ParseInt(header, 10, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user