mirror of
https://github.com/grafana/grafana.git
synced 2025-01-13 01:22:05 -06:00
Auth: id response header (#77871)
* Add config options for identity id response header * Add feature to add identity id response header to all responses * Use util.SplitString
This commit is contained in:
parent
27b7d1de6f
commit
21f94c5b78
@ -565,6 +565,17 @@ azure_auth_enabled = false
|
||||
# Use email lookup in addition to the unique ID provided by the IdP
|
||||
oauth_allow_insecure_email_lookup = false
|
||||
|
||||
# Set to true to include id of identity as a response header
|
||||
id_response_header_enabled = false
|
||||
|
||||
# Prefix used for the id response header, X-Grafana-Identity-Id
|
||||
id_response_header_prefix = X-Grafana
|
||||
|
||||
# List of identity namespaces to add id response headers for, separated by space.
|
||||
# Available namespaces are user, api-key and service-account.
|
||||
# The header value will encode the namespace ("user:<id>", "api-key:<id>", "service-account:<id>")
|
||||
id_response_header_namespaces = user api-key service-account
|
||||
|
||||
#################################### Anonymous Auth ######################
|
||||
[auth.anonymous]
|
||||
# enable anonymous access
|
||||
|
@ -554,6 +554,17 @@
|
||||
# Use email lookup in addition to the unique ID provided by the IdP
|
||||
;oauth_allow_insecure_email_lookup = false
|
||||
|
||||
# Set to true to include id of identity as a response header
|
||||
;id_response_header_enabled = false
|
||||
|
||||
# Prefix used for the id response header, X-Grafana-Identity-Id
|
||||
;id_response_header_prefix = X-Grafana
|
||||
|
||||
# List of identity namespaces to add id response headers for, separated by space.
|
||||
# Available namespaces are user, api-key and service-account.
|
||||
# The header value will encode the namespace ("user:<id>", "api-key:<id>", "service-account:<id>")
|
||||
;id_response_header_namespaces = user api-key service-account
|
||||
|
||||
#################################### Anonymous Auth ######################
|
||||
[auth.anonymous]
|
||||
# enable anonymous access
|
||||
|
@ -4,7 +4,9 @@ package contexthandler
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
@ -135,10 +137,51 @@ func (h *ContextHandler) Middleware(next http.Handler) http.Handler {
|
||||
attribute.Int64("userId", reqContext.UserID),
|
||||
))
|
||||
|
||||
if h.Cfg.IDResponseHeaderEnabled && reqContext.SignedInUser != nil {
|
||||
namespace, id := getNamespaceAndID(reqContext.SignedInUser)
|
||||
reqContext.Resp.Before(h.addIDHeaderEndOfRequestFunc(namespace, id))
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// TODO(kalleep): Refactor to user identity.Requester interface and methods after we have backported this
|
||||
func getNamespaceAndID(user *user.SignedInUser) (string, string) {
|
||||
var namespace, id string
|
||||
if user.UserID > 0 && user.IsServiceAccount {
|
||||
id = strconv.Itoa(int(user.UserID))
|
||||
namespace = "service-account"
|
||||
} else if user.UserID > 0 {
|
||||
id = strconv.Itoa(int(user.UserID))
|
||||
namespace = "user"
|
||||
} else if user.ApiKeyID > 0 {
|
||||
id = strconv.Itoa(int(user.ApiKeyID))
|
||||
namespace = "api-key"
|
||||
}
|
||||
|
||||
return namespace, id
|
||||
}
|
||||
|
||||
func (h *ContextHandler) addIDHeaderEndOfRequestFunc(namespace, id string) web.BeforeFunc {
|
||||
return func(w web.ResponseWriter) {
|
||||
if w.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
if namespace == "" || id == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := h.Cfg.IDResponseHeaderNamespaces[namespace]; !ok {
|
||||
return
|
||||
}
|
||||
|
||||
headerName := fmt.Sprintf("%s-Identity-Id", h.Cfg.IDResponseHeaderPrefix)
|
||||
w.Header().Add(headerName, fmt.Sprintf("%s:%s", namespace, id))
|
||||
}
|
||||
}
|
||||
|
||||
func (h *ContextHandler) deleteInvalidCookieEndOfRequestFunc(reqContext *contextmodel.ReqContext) web.BeforeFunc {
|
||||
return func(w web.ResponseWriter) {
|
||||
if h.features.IsEnabled(reqContext.Req.Context(), featuremgmt.FlagClientTokenRotation) {
|
||||
|
@ -285,6 +285,9 @@ type Cfg struct {
|
||||
AdminEmail string
|
||||
DisableLoginForm bool
|
||||
SignoutRedirectUrl string
|
||||
IDResponseHeaderEnabled bool
|
||||
IDResponseHeaderPrefix string
|
||||
IDResponseHeaderNamespaces map[string]struct{}
|
||||
// Not documented & not supported
|
||||
// stand in until a more complete solution is implemented
|
||||
AuthConfigUIAdminAccess bool
|
||||
@ -1607,6 +1610,17 @@ func readAuthSettings(iniFile *ini.File, cfg *Cfg) (err error) {
|
||||
// Azure Auth
|
||||
AzureAuthEnabled = auth.Key("azure_auth_enabled").MustBool(false)
|
||||
cfg.AzureAuthEnabled = AzureAuthEnabled
|
||||
|
||||
// ID response header
|
||||
cfg.IDResponseHeaderEnabled = auth.Key("id_response_header_enabled").MustBool(false)
|
||||
cfg.IDResponseHeaderPrefix = auth.Key("id_response_header_prefix").MustString("X-Grafana-")
|
||||
|
||||
idHeaderNamespaces := util.SplitString(auth.Key("id_response_header_namespaces").MustString(""))
|
||||
cfg.IDResponseHeaderNamespaces = make(map[string]struct{}, len(idHeaderNamespaces))
|
||||
for _, namespace := range idHeaderNamespaces {
|
||||
cfg.IDResponseHeaderNamespaces[namespace] = struct{}{}
|
||||
}
|
||||
|
||||
readAuthAzureADSettings(cfg)
|
||||
|
||||
// Google Auth
|
||||
|
Loading…
Reference in New Issue
Block a user