mirror of
https://github.com/kemko/nomad.git
synced 2026-01-02 00:15:43 +03:00
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.
71 lines
1.8 KiB
Go
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
|
|
}
|