mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-21 04:49:10 +02:00
Disable ownership on mobile
This commit is contained in:
@@ -87,6 +87,10 @@ func (g *AuthzGate) resolveLevel(id Identity, target Target) AuthzLevel {
|
|||||||
if !target.Owned {
|
if !target.Owned {
|
||||||
return AuthzLevelIdentified
|
return AuthzLevelIdentified
|
||||||
}
|
}
|
||||||
|
// With ownership off, reaching the profile is also reaching its session.
|
||||||
|
if ProfileOwnershipDisabled() {
|
||||||
|
return AuthzLevelSessionHolder
|
||||||
|
}
|
||||||
if holder, running := g.st.SessionHolder(); !running || holder.Matches(id) {
|
if holder, running := g.st.SessionHolder(); !running || holder.Matches(id) {
|
||||||
return AuthzLevelSessionHolder
|
return AuthzLevelSessionHolder
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,6 +176,19 @@ func TestAuthorizeCarriesTheTargetForAPrivilegedCaller(t *testing.T) {
|
|||||||
assert.Equal(t, "/profiles/abcd1111.json", got)
|
assert.Equal(t, "/profiles/abcd1111.json", got)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// With ownership off, somebody else's live session is not a reason to refuse.
|
||||||
|
func TestAuthorizeIgnoresAHeldSessionWhenOwnershipDisabled(t *testing.T) {
|
||||||
|
t.Setenv(EnvDisableProfileOwnership, "true")
|
||||||
|
g := gateFor(t, stubState{
|
||||||
|
target: Target{Path: "/profiles/mine.json", Owned: true},
|
||||||
|
running: true,
|
||||||
|
holder: Principal{Kind: KindUID, Value: "4242"},
|
||||||
|
})
|
||||||
|
|
||||||
|
_, err := g.authorize(transportCtx(unprivUser, nil), servicePath+"Up", &proto.UpRequest{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestAuthorizeBlamesAHeldSession(t *testing.T) {
|
func TestAuthorizeBlamesAHeldSession(t *testing.T) {
|
||||||
g := gateFor(t, stubState{
|
g := gateFor(t, stubState{
|
||||||
target: Target{Path: "/profiles/mine.json", Owned: true},
|
target: Target{Path: "/profiles/mine.json", Owned: true},
|
||||||
|
|||||||
@@ -37,9 +37,15 @@ const EnvDisableProfileOwnership = "NB_DISABLE_PROFILE_OWNERSHIP"
|
|||||||
|
|
||||||
var logProfileOwnershipDisabledOrError sync.Once
|
var logProfileOwnershipDisabledOrError sync.Once
|
||||||
|
|
||||||
// defaultProfileClaimDisabled reports whether the environment turns off
|
// ProfileOwnershipDisabled reports whether profile ownership is turned off, so
|
||||||
// profile ownership. A ownership check will always return true.
|
// every identified caller reaches every profile and controls its session.
|
||||||
func isProfileOwnershipDisabled() bool {
|
//
|
||||||
|
// Mobile records no owners. The app is the only caller and the platform sandbox
|
||||||
|
// already isolates one install from another.
|
||||||
|
func ProfileOwnershipDisabled() bool {
|
||||||
|
if runtime.GOOS == "android" || runtime.GOOS == "ios" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
val := os.Getenv(EnvDisableProfileOwnership)
|
val := os.Getenv(EnvDisableProfileOwnership)
|
||||||
if val == "" {
|
if val == "" {
|
||||||
return false
|
return false
|
||||||
@@ -310,9 +316,6 @@ func looksLikeSID(v string) bool {
|
|||||||
// A principal is a config value, not a caller, so it is never converted into an
|
// A principal is a config value, not a caller, so it is never converted into an
|
||||||
// Identity.
|
// Identity.
|
||||||
func (p Principal) Matches(id Identity) bool {
|
func (p Principal) Matches(id Identity) bool {
|
||||||
if isProfileOwnershipDisabled() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if !id.Known() {
|
if !id.Known() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build !ios && !android
|
||||||
|
|
||||||
package profilemanager
|
package profilemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
//go:build ios || android
|
||||||
|
|
||||||
|
package profilemanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/user"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/client/internal/ipcauth"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MigrateLegacyProfiles is a no-op on mobile
|
||||||
|
func (s *ServiceManager) MigrateLegacyProfiles() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrincipalForUser turns a resolved account into an owner principal.
|
||||||
|
func PrincipalForUser(u *user.User) (string, bool) {
|
||||||
|
if uid, err := strconv.ParseUint(u.Uid, 10, 32); err == nil {
|
||||||
|
return ipcauth.UIDPrincipal(uint32(uid)), true
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build !ios && !android
|
||||||
|
|
||||||
package profilemanager
|
package profilemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ func (p *Profile) AccessibleBy(id ipcauth.Identity) bool {
|
|||||||
if !id.Known() {
|
if !id.Known() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if ipcauth.ProfileOwnershipDisabled() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
if ipcauth.IsPrivilegedCaller(id) {
|
if ipcauth.IsPrivilegedCaller(id) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,19 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/client/internal/ipcauth"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestAccessibleByReachesUnownedProfileWhenOwnershipDisabled(t *testing.T) {
|
||||||
|
t.Setenv(ipcauth.EnvDisableProfileOwnership, "true")
|
||||||
|
|
||||||
|
unowned := Profile{}
|
||||||
|
caller := ipcauth.KnownForTest(ipcauth.Identity{UID: 4242})
|
||||||
|
|
||||||
|
assert.True(t, unowned.AccessibleBy(caller), "an unowned profile is reachable with ownership off")
|
||||||
|
}
|
||||||
|
|
||||||
func withTempConfigDir(t *testing.T, testFunc func(configDir string)) {
|
func withTempConfigDir(t *testing.T, testFunc func(configDir string)) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
tempDir := t.TempDir()
|
tempDir := t.TempDir()
|
||||||
|
|||||||
@@ -60,9 +60,8 @@ type Profile struct {
|
|||||||
type ProfileManager struct {
|
type ProfileManager struct {
|
||||||
configDir string
|
configDir string
|
||||||
username string
|
username string
|
||||||
// identity scopes profile ownership. There is no IPC hop on mobile: the
|
// identity is this app process, which every profile call is made as. Mobile
|
||||||
// manager runs inside the app, so the owner of a profile is the app process
|
// records no owners, see ipcauth.ProfileOwnershipDisabled.
|
||||||
// itself, and the device has a single user anyway.
|
|
||||||
identity ipcauth.Identity
|
identity ipcauth.Identity
|
||||||
serviceMgr *profilemanager.ServiceManager
|
serviceMgr *profilemanager.ServiceManager
|
||||||
mdmLoader *mdm.Loader
|
mdmLoader *mdm.Loader
|
||||||
@@ -167,7 +166,7 @@ func (pm *ProfileManager) AddProfile(displayName string) (*Profile, error) {
|
|||||||
if err := pm.checkProfilesAllowed(); err != nil {
|
if err := pm.checkProfilesAllowed(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
profile, err := pm.serviceMgr.AddProfile(displayName, &pm.identity)
|
profile, err := pm.serviceMgr.AddProfile(displayName, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("add profile: %w", err)
|
return nil, fmt.Errorf("add profile: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user