mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -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
|
# Use email lookup in addition to the unique ID provided by the IdP
|
||||||
oauth_allow_insecure_email_lookup = false
|
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 ######################
|
#################################### Anonymous Auth ######################
|
||||||
[auth.anonymous]
|
[auth.anonymous]
|
||||||
# enable anonymous access
|
# enable anonymous access
|
||||||
|
@ -554,6 +554,17 @@
|
|||||||
# Use email lookup in addition to the unique ID provided by the IdP
|
# Use email lookup in addition to the unique ID provided by the IdP
|
||||||
;oauth_allow_insecure_email_lookup = false
|
;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 ######################
|
#################################### Anonymous Auth ######################
|
||||||
[auth.anonymous]
|
[auth.anonymous]
|
||||||
# enable anonymous access
|
# enable anonymous access
|
||||||
|
@ -4,7 +4,9 @@ package contexthandler
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"go.opentelemetry.io/otel/attribute"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
"go.opentelemetry.io/otel/trace"
|
"go.opentelemetry.io/otel/trace"
|
||||||
@ -135,10 +137,51 @@ func (h *ContextHandler) Middleware(next http.Handler) http.Handler {
|
|||||||
attribute.Int64("userId", reqContext.UserID),
|
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)
|
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 {
|
func (h *ContextHandler) deleteInvalidCookieEndOfRequestFunc(reqContext *contextmodel.ReqContext) web.BeforeFunc {
|
||||||
return func(w web.ResponseWriter) {
|
return func(w web.ResponseWriter) {
|
||||||
if h.features.IsEnabled(reqContext.Req.Context(), featuremgmt.FlagClientTokenRotation) {
|
if h.features.IsEnabled(reqContext.Req.Context(), featuremgmt.FlagClientTokenRotation) {
|
||||||
|
@ -285,6 +285,9 @@ type Cfg struct {
|
|||||||
AdminEmail string
|
AdminEmail string
|
||||||
DisableLoginForm bool
|
DisableLoginForm bool
|
||||||
SignoutRedirectUrl string
|
SignoutRedirectUrl string
|
||||||
|
IDResponseHeaderEnabled bool
|
||||||
|
IDResponseHeaderPrefix string
|
||||||
|
IDResponseHeaderNamespaces map[string]struct{}
|
||||||
// Not documented & not supported
|
// Not documented & not supported
|
||||||
// stand in until a more complete solution is implemented
|
// stand in until a more complete solution is implemented
|
||||||
AuthConfigUIAdminAccess bool
|
AuthConfigUIAdminAccess bool
|
||||||
@ -1607,6 +1610,17 @@ func readAuthSettings(iniFile *ini.File, cfg *Cfg) (err error) {
|
|||||||
// Azure Auth
|
// Azure Auth
|
||||||
AzureAuthEnabled = auth.Key("azure_auth_enabled").MustBool(false)
|
AzureAuthEnabled = auth.Key("azure_auth_enabled").MustBool(false)
|
||||||
cfg.AzureAuthEnabled = AzureAuthEnabled
|
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)
|
readAuthAzureADSettings(cfg)
|
||||||
|
|
||||||
// Google Auth
|
// Google Auth
|
||||||
|
Loading…
Reference in New Issue
Block a user