56 lines
1.9 KiB
Go
56 lines
1.9 KiB
Go
|
|
package security
|
||
|
|
|
||
|
|
// SecurityBag is the request-scoped security context for a single request.
|
||
|
|
// It carries the authenticated [Identity] alongside any additional attributes
|
||
|
|
// injected during the enrichment phase (hardware IDs, grant codes, etc.).
|
||
|
|
//
|
||
|
|
// SecurityBag is a value type — all mutation methods return a new value without
|
||
|
|
// modifying the receiver. The attribute map is copied on every [SecurityBag.With]
|
||
|
|
// call to preserve this guarantee.
|
||
|
|
//
|
||
|
|
// The framework defines no string key constants for bag attributes — all
|
||
|
|
// framework-known fields live as typed fields on [Identity]. Callers define
|
||
|
|
// their own constants to avoid collisions:
|
||
|
|
//
|
||
|
|
// const KeyHardwareID = "hardware_id"
|
||
|
|
//
|
||
|
|
// bag.With(KeyHardwareID, hwID)
|
||
|
|
// val, ok := bag.Get(KeyHardwareID)
|
||
|
|
type SecurityBag struct {
|
||
|
|
identity Identity
|
||
|
|
attributes map[string]any
|
||
|
|
}
|
||
|
|
|
||
|
|
// NewSecurityBag creates a SecurityBag wrapping id with an empty attribute map.
|
||
|
|
func NewSecurityBag(id Identity) SecurityBag {
|
||
|
|
return SecurityBag{identity: id}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Identity returns the authenticated Identity stored in the bag.
|
||
|
|
func (b SecurityBag) Identity() Identity {
|
||
|
|
return b.identity
|
||
|
|
}
|
||
|
|
|
||
|
|
// WithIdentity returns a copy of the bag with the Identity replaced by id.
|
||
|
|
// Used by bag enrichers that modify the Identity (e.g., [authmw.WithTenantHeader]).
|
||
|
|
func (b SecurityBag) WithIdentity(id Identity) SecurityBag {
|
||
|
|
return SecurityBag{identity: id, attributes: b.attributes}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get returns the attribute stored under key and true, or (nil, false) if absent.
|
||
|
|
func (b SecurityBag) Get(key string) (any, bool) {
|
||
|
|
v, ok := b.attributes[key]
|
||
|
|
return v, ok
|
||
|
|
}
|
||
|
|
|
||
|
|
// With returns a copy of the bag with key set to value.
|
||
|
|
// The receiver is not modified — safe to call from concurrent middleware chains.
|
||
|
|
func (b SecurityBag) With(key string, value any) SecurityBag {
|
||
|
|
attrs := make(map[string]any, len(b.attributes)+1)
|
||
|
|
for k, v := range b.attributes {
|
||
|
|
attrs[k] = v
|
||
|
|
}
|
||
|
|
attrs[key] = value
|
||
|
|
return SecurityBag{identity: b.identity, attributes: attrs}
|
||
|
|
}
|