Files
nomad/lib/auth/oidc/request.go
Daniel Bennett 6a06653032 auth: decrease size of oidc request cache (#25371)
if the auth-url api is getting DOS'd,
then we do not expect it to still function;
we only protect the rest of the system.

users will need to use a break-glass ACL
token if they need Nomad UI/API access
during such a denial of service.
2025-03-12 12:37:47 -05:00

71 lines
1.8 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package oidc
import (
"errors"
"time"
"github.com/hashicorp/cap/oidc"
"github.com/hashicorp/golang-lru/v2/expirable"
)
var (
ErrNonceReuse = errors.New("nonce reuse detected")
// ErrTooManyRequests is returned if the request cache is full.
// Realistically, we expect this only to happen if the auth-url
// API endpoint is being DOS'd.
ErrTooManyRequests = errors.New("too many auth requests")
)
// MaxRequests is how many requests are allowed to be stored at a time.
// It needs to be large enough for legitimate user traffic, but small enough
// to prevent a DOS from eating up server memory.
const MaxRequests = 1000
// NewRequestCache creates a cache for OIDC requests.
// The JWT expiration time in the cap library is 5 minutes,
// so timeout should be around that long.
func NewRequestCache(timeout time.Duration) *RequestCache {
return &RequestCache{
c: expirable.NewLRU[string, *oidc.Req](MaxRequests, nil, timeout),
}
}
type RequestCache struct {
c *expirable.LRU[string, *oidc.Req]
}
// Store saves the request, to be Loaded later with its Nonce.
// If LoadAndDelete is not called, the stale request will be auto-deleted.
func (rc *RequestCache) Store(req *oidc.Req) error {
if rc.c.Len() >= MaxRequests {
return ErrTooManyRequests
}
if _, ok := rc.c.Get(req.Nonce()); ok {
// we already had a request for this nonce (should never happen)
return ErrNonceReuse
}
rc.c.Add(req.Nonce(), req)
return nil
}
func (rc *RequestCache) Load(nonce string) *oidc.Req {
if req, ok := rc.c.Get(nonce); ok {
return req
}
return nil
}
func (rc *RequestCache) LoadAndDelete(nonce string) *oidc.Req {
if req, ok := rc.c.Get(nonce); ok {
rc.c.Remove(nonce)
return req
}
return nil
}