mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-25 13:59:08 +01:00
Small refactor of Authz
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package ipcauth
|
||||
|
||||
import (
|
||||
"google.golang.org/grpc/codes"
|
||||
gstatus "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
@@ -46,45 +47,47 @@ func (l AuthzLevel) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
// resolveLevel is the authority the caller holds over the profile the request
|
||||
// resolved to. A profile the caller does not own confers nothing beyond being
|
||||
// identified, which is also what an unresolved handle leaves them with.
|
||||
func resolveLevel(id Identity, target Target, st DaemonState) AuthzLevel {
|
||||
if !id.Known() {
|
||||
return AuthzLevelNone
|
||||
// RequireLevel builds a rule from a level, for composing inside another rule.
|
||||
func RequireLevel(want AuthzLevel) Rule {
|
||||
return func(r Request) error {
|
||||
if r.Level >= want {
|
||||
return nil
|
||||
}
|
||||
return denyLevel(r, want)
|
||||
}
|
||||
if IsPrivilegedCaller(id) {
|
||||
return AuthzLevelPrivileged
|
||||
}
|
||||
if !target.Owned {
|
||||
return AuthzLevelIdentified
|
||||
}
|
||||
if holder, running := st.SessionHolder(); !running || holder.Matches(id) {
|
||||
return AuthzLevelSessionHolder
|
||||
}
|
||||
return AuthzLevelProfileOwner
|
||||
}
|
||||
|
||||
// presentableHandleError keeps a resolution failure only when the gate can put
|
||||
// it in front of the caller in place of its own refusal. Everything else is
|
||||
// dropped, and the caller gets the refusal their level earned.
|
||||
func presentableHandleError(handle string, err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
func denyLevel(r Request, want AuthzLevel) error {
|
||||
return gstatus.Errorf(codes.PermissionDenied,
|
||||
"%s requires %s, caller %s is %s", r.Method, want, r.Identity, r.Level)
|
||||
}
|
||||
|
||||
// denyPolicyLevel refuses a caller at the gate, where the policy is in hand.
|
||||
//
|
||||
// Requiring privilege is the one denial a caller can act on, so it carries the
|
||||
// elevated command rather than a bare refusal. A privileged method that declares
|
||||
// no action keeps the plain message. Rules deny through denyLevel instead: they
|
||||
// cannot reach the policy table without an initialization cycle, and no rule
|
||||
// requires privilege.
|
||||
func denyPolicyLevel(r Request, p MethodPolicy) error {
|
||||
switch p.Level {
|
||||
case AuthzLevelPrivileged:
|
||||
if p.Action != "" {
|
||||
actor, command := RequiredActor(p.Command)
|
||||
return PrivilegeError(PrivilegeSummary(p.Action, actor), command)
|
||||
}
|
||||
|
||||
case AuthzLevelSessionHolder:
|
||||
// resolveLevel stops at profile owner only when a session is running and
|
||||
// somebody else holds it.
|
||||
if r.Level == AuthzLevelProfileOwner {
|
||||
return SessionHeldError(p.Action)
|
||||
}
|
||||
return NotOwnerError(p.Action)
|
||||
|
||||
// An empty handle is the active profile rather than something the caller
|
||||
// typed, so a failure to resolve it is not theirs to correct.
|
||||
if handle == "" {
|
||||
return nil
|
||||
case AuthzLevelProfileOwner:
|
||||
return NotOwnerError(p.Action)
|
||||
}
|
||||
|
||||
// Only a gRPC status reaches the caller as a sentence the CLI and the UI
|
||||
// render. A plain error is a daemon-side failure, and putting it on the
|
||||
// wire would tell the caller about the daemon rather than about the handle
|
||||
// they gave.
|
||||
if _, ok := gstatus.FromError(err); !ok {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
return denyLevel(r, p.Level)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user