mirror of
https://github.com/netbirdio/netbird.git
synced 2026-08-29 02:51:29 +02:00
102 lines
4.0 KiB
Go
102 lines
4.0 KiB
Go
package ipcauth
|
|
|
|
import "sync"
|
|
|
|
const servicePath = "/daemon.DaemonService/"
|
|
|
|
// ProfilePolicy exposes the active profile's ownership to the interceptor. The
|
|
// daemon server implements it. ConfigAdapter bridges the gap because the gRPC
|
|
// server (and its interceptor) is constructed before the server instance exists.
|
|
type ProfilePolicy interface {
|
|
// ActiveProfileOwnership returns the active profile's ownership policy.
|
|
ActiveProfileOwnership() Ownership
|
|
|
|
// ClaimActiveProfileOwnerIfUnowned atomically claims the active profile for
|
|
// id when it has no owners and is not shared (trust-on-first-use), and
|
|
// reports whether id is now an owner. A false return means the profile was
|
|
// already owned/shared or another caller won the claim.
|
|
ClaimActiveProfileOwnerIfUnowned(id Identity) (bool, error)
|
|
}
|
|
|
|
// handlerAuthorizedMethods bypass the active-profile gate. Peer identity is
|
|
// still required to reach them. Two groups:
|
|
//
|
|
// - Per-user / per-target-profile operations whose handler does its own
|
|
// authorization bound to the caller identity: AddProfile, ListProfiles,
|
|
// GetActiveProfile, RemoveProfile, RenameProfile, and SwitchProfile (gated
|
|
// on the TARGET profile's ownership via authorizeTargetProfile).
|
|
// - Connection-lifecycle operations on the single shared daemon connection
|
|
// that any authenticated local user may perform: Down. Gating these on the
|
|
// ACTIVE profile's owner would trap a user behind another user's profile —
|
|
// they could neither disconnect nor switch to their OWN profile. SwitchProfile
|
|
// is bounded by its target check; Down only tears the connection down.
|
|
var handlerAuthorizedMethods = map[string]bool{
|
|
servicePath + "AddProfile": true,
|
|
servicePath + "ListProfiles": true,
|
|
servicePath + "GetActiveProfile": true,
|
|
servicePath + "RemoveProfile": true,
|
|
servicePath + "RenameProfile": true,
|
|
servicePath + "SwitchProfile": true,
|
|
servicePath + "Down": true,
|
|
}
|
|
|
|
// auditMethods are worth an audit log line. Denials are always logged.
|
|
var auditMethods = map[string]bool{
|
|
servicePath + "GetConfig": true,
|
|
servicePath + "SetConfig": true,
|
|
servicePath + "Login": true,
|
|
servicePath + "WaitSSOLogin": true,
|
|
servicePath + "RequestJWTAuth": true,
|
|
servicePath + "WaitJWTToken": true,
|
|
servicePath + "StartCapture": true,
|
|
servicePath + "StartBundleCapture": true,
|
|
servicePath + "DebugBundle": true,
|
|
servicePath + "ExposeService": true,
|
|
servicePath + "Up": true,
|
|
servicePath + "Down": true,
|
|
servicePath + "SelectNetworks": true,
|
|
servicePath + "DeselectNetworks": true,
|
|
servicePath + "SwitchProfile": true,
|
|
servicePath + "TriggerUpdate": true,
|
|
servicePath + "Logout": true,
|
|
servicePath + "CleanState": true,
|
|
servicePath + "DeleteState": true,
|
|
}
|
|
|
|
// ConfigAdapter is a ProfilePolicy whose backend is set lazily, once the daemon
|
|
// server instance is created. Until then it reports an unowned profile
|
|
// (Ownership zero value), so non-privileged callers are denied.
|
|
type ConfigAdapter struct {
|
|
mu sync.RWMutex
|
|
backend ProfilePolicy
|
|
}
|
|
|
|
// SetBackend installs the real policy. Must be called before serving RPCs.
|
|
func (a *ConfigAdapter) SetBackend(backend ProfilePolicy) {
|
|
a.mu.Lock()
|
|
defer a.mu.Unlock()
|
|
a.backend = backend
|
|
}
|
|
|
|
// ActiveProfileOwnership delegates to the backend, or reports an unowned profile
|
|
// when no backend is set yet.
|
|
func (a *ConfigAdapter) ActiveProfileOwnership() Ownership {
|
|
a.mu.RLock()
|
|
defer a.mu.RUnlock()
|
|
if a.backend == nil {
|
|
return Ownership{}
|
|
}
|
|
return a.backend.ActiveProfileOwnership()
|
|
}
|
|
|
|
// ClaimActiveProfileOwnerIfUnowned delegates to the backend. Before the backend
|
|
// is set it cannot claim, so it reports not-owned (fail closed).
|
|
func (a *ConfigAdapter) ClaimActiveProfileOwnerIfUnowned(id Identity) (bool, error) {
|
|
a.mu.RLock()
|
|
defer a.mu.RUnlock()
|
|
if a.backend == nil {
|
|
return false, nil
|
|
}
|
|
return a.backend.ClaimActiveProfileOwnerIfUnowned(id)
|
|
}
|