mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2026-06-19 00:33:03 +03:00
Compare commits
3 Commits
docs-secur
...
vmatuh-jwt
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b86347f10d | ||
|
|
8cd01e0040 | ||
|
|
1840a3838e |
@@ -20,6 +20,7 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/jwt"
|
||||
"github.com/VictoriaMetrics/metrics"
|
||||
"github.com/cespare/xxhash/v2"
|
||||
"gopkg.in/yaml.v2"
|
||||
@@ -127,11 +128,11 @@ func (ui *UserInfo) beginConcurrencyLimit(ctx context.Context) error {
|
||||
// The current request couldn't be executed until the request timeout.
|
||||
ui.concurrencyLimitReached.Inc()
|
||||
return fmt.Errorf("cannot start executing the request during -maxQueueDuration=%s because %d concurrent requests from the user %s are executed",
|
||||
*maxQueueDuration, ui.getMaxConcurrentRequests(), ui.name())
|
||||
*maxQueueDuration, ui.getMaxConcurrentRequests(), userName(ui, nil))
|
||||
}
|
||||
|
||||
return fmt.Errorf("cannot start executing the request because %d concurrent requests from the user %s are executed: %w",
|
||||
ui.getMaxConcurrentRequests(), ui.name(), err)
|
||||
ui.getMaxConcurrentRequests(), userName(ui, nil), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1010,7 +1011,7 @@ func parseAuthConfigUsers(ac *AuthConfig) (map[string]*UserInfo, error) {
|
||||
var labelNameRegexp = regexp.MustCompile("^[a-zA-Z_:.][a-zA-Z0-9_:.]*$")
|
||||
|
||||
func (ui *UserInfo) getMetricLabels() (string, error) {
|
||||
name := ui.name()
|
||||
name := userName(ui, nil)
|
||||
if len(name) == 0 && len(ui.MetricLabels) == 0 {
|
||||
// fast path
|
||||
return "", nil
|
||||
@@ -1115,24 +1116,6 @@ func (ui *UserInfo) initURLs() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ui *UserInfo) name() string {
|
||||
if ui.Name != "" {
|
||||
return ui.Name
|
||||
}
|
||||
if ui.Username != "" {
|
||||
return ui.Username
|
||||
}
|
||||
if ui.BearerToken != "" {
|
||||
h := xxhash.Sum64([]byte(ui.BearerToken))
|
||||
return fmt.Sprintf("bearer_token:hash:%016X", h)
|
||||
}
|
||||
if ui.AuthToken != "" {
|
||||
h := xxhash.Sum64([]byte(ui.AuthToken))
|
||||
return fmt.Sprintf("auth_token:hash:%016X", h)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getAuthTokens(authToken, bearerToken, username, password string) ([]string, error) {
|
||||
if authToken != "" {
|
||||
if bearerToken != "" {
|
||||
@@ -1236,3 +1219,36 @@ func sanitizeURLPrefix(urlPrefix *url.URL) (*url.URL, error) {
|
||||
}
|
||||
return urlPrefix, nil
|
||||
}
|
||||
|
||||
func userName(ui *UserInfo, tkn *jwt.Token) string {
|
||||
if tkn != nil {
|
||||
if sub := tkn.Subject(); sub != "" {
|
||||
return "jwt:sub:" + sub
|
||||
}
|
||||
if iss := tkn.Issuer(); iss != "" {
|
||||
return "jwt:iss:" + iss
|
||||
}
|
||||
|
||||
return "jwt:unknown"
|
||||
}
|
||||
|
||||
if ui.Name != "" {
|
||||
return ui.Name
|
||||
}
|
||||
if ui.Username != "" {
|
||||
return ui.Username
|
||||
}
|
||||
if ui.BearerToken != "" {
|
||||
h := xxhash.Sum64([]byte(ui.BearerToken))
|
||||
return fmt.Sprintf("bearer_token:hash:%016X", h)
|
||||
}
|
||||
if ui.AuthToken != "" {
|
||||
h := xxhash.Sum64([]byte(ui.AuthToken))
|
||||
return fmt.Sprintf("auth_token:hash:%016X", h)
|
||||
}
|
||||
if ui.JWT != nil {
|
||||
return "jwt"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool {
|
||||
}
|
||||
if ui, tkn := getUserInfoByJWTToken(ats); ui != nil {
|
||||
if tkn == nil {
|
||||
logger.Panicf("BUG: unexpected nil jwt token for user %q", ui.name())
|
||||
logger.Panicf("BUG: unexpected nil jwt token for user %q", userName(ui, nil))
|
||||
}
|
||||
|
||||
processUserRequest(w, r, ui, tkn)
|
||||
@@ -253,7 +253,7 @@ func processUserRequest(w http.ResponseWriter, r *http.Request, ui *UserInfo, tk
|
||||
}
|
||||
|
||||
// Read the initial chunk for the request body.
|
||||
userName := ui.name()
|
||||
userName := userName(ui, tkn)
|
||||
if userName == "" {
|
||||
userName = "unauthorized"
|
||||
}
|
||||
@@ -412,7 +412,7 @@ func processRequest(w http.ResponseWriter, r *http.Request, ui *UserInfo, tkn *j
|
||||
ui.backendErrors.Inc()
|
||||
}
|
||||
err := &httpserver.ErrorWithStatusCode{
|
||||
Err: fmt.Errorf("all the %d backends for the user %q are unavailable for proxying the request - check previous WARN logs to see the exact error for each failed backend", up.getBackendsCount(), ui.name()),
|
||||
Err: fmt.Errorf("all the %d backends for the user %q are unavailable for proxying the request - check previous WARN logs to see the exact error for each failed backend", up.getBackendsCount(), userName(ui, tkn)),
|
||||
StatusCode: http.StatusBadGateway,
|
||||
}
|
||||
httpserver.Errorf(w, r, "%s", err)
|
||||
|
||||
@@ -50,6 +50,8 @@ type body struct {
|
||||
Iat int64 `json:"iat"`
|
||||
Jti string `json:"jti,omitempty"`
|
||||
Scope string `json:"scope,omitempty"`
|
||||
Sub string `json:"sub,omitempty"`
|
||||
Iss string `json:"iss,omitempty"`
|
||||
VMAccess *VMAccessClaim `json:"vm_access"`
|
||||
}
|
||||
|
||||
@@ -207,6 +209,14 @@ func (t *Token) VMAccess() *VMAccessClaim {
|
||||
return t.body.VMAccess
|
||||
}
|
||||
|
||||
func (t *Token) Subject() string {
|
||||
return t.body.Sub
|
||||
}
|
||||
|
||||
func (t *Token) Issuer() string {
|
||||
return t.body.Iss
|
||||
}
|
||||
|
||||
func parseJWTHeader(data string) (*header, error) {
|
||||
var jh header
|
||||
decoded, err := decodeB64([]byte(data))
|
||||
@@ -226,6 +236,8 @@ func parseJWTBody(data string) (*body, error) {
|
||||
// issued at time unix_ts
|
||||
Iat int64 `json:"iat"`
|
||||
Jti string `json:"jti,omitempty"`
|
||||
Sub string `json:"sub,omitempty"`
|
||||
Iss string `json:"iss,omitempty"`
|
||||
Scope json.RawMessage `json:"scope,omitempty"`
|
||||
// store as raw message to support different types
|
||||
VMAccess *json.RawMessage `json:"vm_access"`
|
||||
@@ -274,6 +286,8 @@ func parseJWTBody(data string) (*body, error) {
|
||||
Exp: tb.Exp,
|
||||
Iat: tb.Iat,
|
||||
Jti: tb.Jti,
|
||||
Sub: tb.Sub,
|
||||
Iss: tb.Iss,
|
||||
Scope: scope,
|
||||
VMAccess: &a,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user