|
|
|
@ -90,84 +90,90 @@ func FromContext(c context.Context) *models.ReqContext { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Middleware provides a middleware to initialize the Macaron context.
|
|
|
|
|
func (h *ContextHandler) Middleware(mContext *web.Context) { |
|
|
|
|
_, span := h.tracer.Start(mContext.Req.Context(), "Auth - Middleware") |
|
|
|
|
defer span.End() |
|
|
|
|
// Middleware provides a middleware to initialize the request context.
|
|
|
|
|
func (h *ContextHandler) Middleware(next http.Handler) http.Handler { |
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
|
|
|
ctx := r.Context() |
|
|
|
|
mContext := web.FromContext(ctx) |
|
|
|
|
_, span := h.tracer.Start(ctx, "Auth - Middleware") |
|
|
|
|
defer span.End() |
|
|
|
|
|
|
|
|
|
reqContext := &models.ReqContext{ |
|
|
|
|
Context: mContext, |
|
|
|
|
SignedInUser: &user.SignedInUser{}, |
|
|
|
|
IsSignedIn: false, |
|
|
|
|
AllowAnonymous: false, |
|
|
|
|
SkipCache: false, |
|
|
|
|
Logger: log.New("context"), |
|
|
|
|
} |
|
|
|
|
reqContext := &models.ReqContext{ |
|
|
|
|
Context: mContext, |
|
|
|
|
SignedInUser: &user.SignedInUser{}, |
|
|
|
|
IsSignedIn: false, |
|
|
|
|
AllowAnonymous: false, |
|
|
|
|
SkipCache: false, |
|
|
|
|
Logger: log.New("context"), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Inject ReqContext into http.Request.Context
|
|
|
|
|
mContext.Req = mContext.Req.WithContext(ctxkey.Set(mContext.Req.Context(), reqContext)) |
|
|
|
|
// Inject ReqContext into http.Request.Context
|
|
|
|
|
*r = *r.WithContext(context.WithValue(ctx, reqContextKey{}, reqContext)) |
|
|
|
|
|
|
|
|
|
traceID := tracing.TraceIDFromContext(mContext.Req.Context(), false) |
|
|
|
|
if traceID != "" { |
|
|
|
|
reqContext.Logger = reqContext.Logger.New("traceID", traceID) |
|
|
|
|
} |
|
|
|
|
traceID := tracing.TraceIDFromContext(mContext.Req.Context(), false) |
|
|
|
|
if traceID != "" { |
|
|
|
|
reqContext.Logger = reqContext.Logger.New("traceID", traceID) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const headerName = "X-Grafana-Org-Id" |
|
|
|
|
orgID := int64(0) |
|
|
|
|
orgIDHeader := reqContext.Req.Header.Get(headerName) |
|
|
|
|
if orgIDHeader != "" { |
|
|
|
|
id, err := strconv.ParseInt(orgIDHeader, 10, 64) |
|
|
|
|
if err == nil { |
|
|
|
|
orgID = id |
|
|
|
|
} else { |
|
|
|
|
reqContext.Logger.Debug("Received invalid header", "header", headerName, "value", orgIDHeader) |
|
|
|
|
const headerName = "X-Grafana-Org-Id" |
|
|
|
|
orgID := int64(0) |
|
|
|
|
orgIDHeader := reqContext.Req.Header.Get(headerName) |
|
|
|
|
if orgIDHeader != "" { |
|
|
|
|
id, err := strconv.ParseInt(orgIDHeader, 10, 64) |
|
|
|
|
if err == nil { |
|
|
|
|
orgID = id |
|
|
|
|
} else { |
|
|
|
|
reqContext.Logger.Debug("Received invalid header", "header", headerName, "value", orgIDHeader) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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) |
|
|
|
|
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
|
|
|
|
|
// then look for api key in session (special case for render calls via api)
|
|
|
|
|
// then test if anonymous access is enabled
|
|
|
|
|
switch { |
|
|
|
|
case h.initContextWithRenderAuth(reqContext): |
|
|
|
|
case h.initContextWithAPIKey(reqContext): |
|
|
|
|
case h.initContextWithBasicAuth(reqContext, orgID): |
|
|
|
|
case h.initContextWithAuthProxy(reqContext, orgID): |
|
|
|
|
case h.initContextWithToken(reqContext, orgID): |
|
|
|
|
case h.initContextWithJWT(reqContext, orgID): |
|
|
|
|
case h.initContextWithAnonymousUser(reqContext): |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
reqContext.Logger = reqContext.Logger.New("userId", reqContext.UserID, "orgId", reqContext.OrgID, "uname", reqContext.Login) |
|
|
|
|
span.AddEvents( |
|
|
|
|
[]string{"uname", "orgId", "userId"}, |
|
|
|
|
[]tracing.EventValue{ |
|
|
|
|
{Str: reqContext.Login}, |
|
|
|
|
{Num: reqContext.OrgID}, |
|
|
|
|
{Num: reqContext.UserID}}, |
|
|
|
|
) |
|
|
|
|
// 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
|
|
|
|
|
// then look for api key in session (special case for render calls via api)
|
|
|
|
|
// then test if anonymous access is enabled
|
|
|
|
|
switch { |
|
|
|
|
case h.initContextWithRenderAuth(reqContext): |
|
|
|
|
case h.initContextWithAPIKey(reqContext): |
|
|
|
|
case h.initContextWithBasicAuth(reqContext, orgID): |
|
|
|
|
case h.initContextWithAuthProxy(reqContext, orgID): |
|
|
|
|
case h.initContextWithToken(reqContext, orgID): |
|
|
|
|
case h.initContextWithJWT(reqContext, orgID): |
|
|
|
|
case h.initContextWithAnonymousUser(reqContext): |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// update last seen every 5min
|
|
|
|
|
if reqContext.ShouldUpdateLastSeenAt() { |
|
|
|
|
reqContext.Logger.Debug("Updating last user_seen_at", "user_id", reqContext.UserID) |
|
|
|
|
if err := h.userService.UpdateLastSeenAt(mContext.Req.Context(), &user.UpdateUserLastSeenAtCommand{UserID: reqContext.UserID}); err != nil { |
|
|
|
|
reqContext.Logger.Error("Failed to update last_seen_at", "error", err) |
|
|
|
|
reqContext.Logger = reqContext.Logger.New("userId", reqContext.UserID, "orgId", reqContext.OrgID, "uname", reqContext.Login) |
|
|
|
|
span.AddEvents( |
|
|
|
|
[]string{"uname", "orgId", "userId"}, |
|
|
|
|
[]tracing.EventValue{ |
|
|
|
|
{Str: reqContext.Login}, |
|
|
|
|
{Num: reqContext.OrgID}, |
|
|
|
|
{Num: reqContext.UserID}}, |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
// update last seen every 5min
|
|
|
|
|
if reqContext.ShouldUpdateLastSeenAt() { |
|
|
|
|
reqContext.Logger.Debug("Updating last user_seen_at", "user_id", reqContext.UserID) |
|
|
|
|
if err := h.userService.UpdateLastSeenAt(mContext.Req.Context(), &user.UpdateUserLastSeenAtCommand{UserID: reqContext.UserID}); err != nil { |
|
|
|
|
reqContext.Logger.Error("Failed to update last_seen_at", "error", err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
next.ServeHTTP(w, r) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (h *ContextHandler) initContextWithAnonymousUser(reqContext *models.ReqContext) bool { |
|
|
|
|