-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
feat: add MDM managed app configuration support for Android and iOS #5986
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
dbrieck
wants to merge
3
commits into
netbirdio:main
Choose a base branch
from
dbrieck:feat/mdm-managed-config
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
5d8c87a
feat: add MDM managed app configuration support for Android and iOS
dbrieck-pengate f216e7a
fix: address CodeRabbit review feedback on MDM managed config
dbrieck-pengate b517419
fix: add GetManagementURL getter and pass mgmt URL to NewAuth
dbrieck-pengate File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,195 @@ | ||
| package android | ||
|
|
||
| import ( | ||
| "fmt" | ||
|
|
||
| log "github.com/sirupsen/logrus" | ||
|
|
||
| "github.com/netbirdio/netbird/client/internal/profilemanager" | ||
| ) | ||
|
|
||
| // Managed configuration key names for Android Enterprise managed configurations. | ||
| // These match the keys defined in app_restrictions.xml on the Android native app side. | ||
| const ( | ||
| managedConfigKeyManagementURL = "managementUrl" | ||
| managedConfigKeySetupKey = "setupKey" | ||
| managedConfigKeyAdminURL = "adminUrl" | ||
| managedConfigKeyPreSharedKey = "preSharedKey" | ||
| managedConfigKeyRosenpassEnabled = "rosenpassEnabled" | ||
| managedConfigKeyRosenpassPerm = "rosenpassPermissive" | ||
| managedConfigKeyDisableAutoConn = "disableAutoConnect" | ||
| ) | ||
|
|
||
| // Key name getters for the Android Java client to reference the same key constants. | ||
|
|
||
| // GetManagedConfigKeyManagementURL returns the key name for management URL | ||
| func GetManagedConfigKeyManagementURL() string { return managedConfigKeyManagementURL } | ||
|
|
||
| // GetManagedConfigKeySetupKey returns the key name for setup key | ||
| func GetManagedConfigKeySetupKey() string { return managedConfigKeySetupKey } | ||
|
|
||
| // GetManagedConfigKeyAdminURL returns the key name for admin URL | ||
| func GetManagedConfigKeyAdminURL() string { return managedConfigKeyAdminURL } | ||
|
|
||
| // GetManagedConfigKeyPreSharedKey returns the key name for pre-shared key | ||
| func GetManagedConfigKeyPreSharedKey() string { return managedConfigKeyPreSharedKey } | ||
|
|
||
| // GetManagedConfigKeyRosenpassEnabled returns the key name for Rosenpass enabled | ||
| func GetManagedConfigKeyRosenpassEnabled() string { return managedConfigKeyRosenpassEnabled } | ||
|
|
||
| // GetManagedConfigKeyRosenpassPermissive returns the key name for Rosenpass permissive | ||
| func GetManagedConfigKeyRosenpassPermissive() string { return managedConfigKeyRosenpassPerm } | ||
|
|
||
| // GetManagedConfigKeyDisableAutoConnect returns the key name for disable auto-connect | ||
| func GetManagedConfigKeyDisableAutoConnect() string { return managedConfigKeyDisableAutoConn } | ||
|
|
||
| // ManagedConfig holds configuration values pushed by an MDM/EMM via Android Enterprise | ||
| // managed configurations (app restrictions). Values set here override user preferences | ||
| // on every app launch. | ||
| // | ||
| // The native Android app reads from RestrictionsManager and populates this struct | ||
| // via the setter methods, then calls Apply() to write the values to the config file. | ||
| type ManagedConfig struct { | ||
| managementURL string | ||
| setupKey string | ||
| adminURL string | ||
| preSharedKey *string | ||
| rosenpassEnabled *bool | ||
| rosenpassPerm *bool | ||
| disableAutoConn *bool | ||
| } | ||
|
|
||
| // NewManagedConfig creates a new empty ManagedConfig | ||
| func NewManagedConfig() *ManagedConfig { | ||
| return &ManagedConfig{} | ||
| } | ||
|
|
||
| // SetManagementURL sets the management server URL from MDM config | ||
| func (m *ManagedConfig) SetManagementURL(url string) { | ||
| m.managementURL = url | ||
| } | ||
|
|
||
| // SetSetupKey sets the setup key for silent device registration from MDM config | ||
| func (m *ManagedConfig) SetSetupKey(key string) { | ||
| m.setupKey = key | ||
| } | ||
|
|
||
| // SetAdminURL sets the admin dashboard URL from MDM config | ||
| func (m *ManagedConfig) SetAdminURL(url string) { | ||
| m.adminURL = url | ||
| } | ||
|
|
||
| // SetPreSharedKey sets the WireGuard pre-shared key from MDM config. | ||
| // An empty string is treated as absent (no override). | ||
| func (m *ManagedConfig) SetPreSharedKey(key string) { | ||
| if key == "" { | ||
| return | ||
| } | ||
| m.preSharedKey = &key | ||
| } | ||
|
|
||
| // SetRosenpassEnabled sets whether Rosenpass post-quantum encryption is enabled | ||
| func (m *ManagedConfig) SetRosenpassEnabled(enabled bool) { | ||
| m.rosenpassEnabled = &enabled | ||
| } | ||
|
|
||
| // SetRosenpassPermissive sets whether Rosenpass permissive mode is enabled | ||
| func (m *ManagedConfig) SetRosenpassPermissive(permissive bool) { | ||
| m.rosenpassPerm = &permissive | ||
| } | ||
|
|
||
| // SetDisableAutoConnect sets whether auto-connect on launch is disabled | ||
| func (m *ManagedConfig) SetDisableAutoConnect(disable bool) { | ||
| m.disableAutoConn = &disable | ||
| } | ||
|
|
||
| // HasSetupKey returns true if a setup key was provided by MDM | ||
| func (m *ManagedConfig) HasSetupKey() bool { | ||
| return m.setupKey != "" | ||
| } | ||
|
|
||
| // GetSetupKey returns the MDM-provided setup key | ||
| func (m *ManagedConfig) GetSetupKey() string { | ||
| return m.setupKey | ||
| } | ||
|
|
||
| // GetManagementURL returns the MDM-provided management URL | ||
| func (m *ManagedConfig) GetManagementURL() string { | ||
| return m.managementURL | ||
| } | ||
|
|
||
| // HasConfig returns true if any configuration value was set by MDM | ||
| func (m *ManagedConfig) HasConfig() bool { | ||
| return m.managementURL != "" || | ||
| m.setupKey != "" || | ||
| m.adminURL != "" || | ||
| m.preSharedKey != nil || | ||
| m.rosenpassEnabled != nil || | ||
| m.rosenpassPerm != nil || | ||
| m.disableAutoConn != nil | ||
| } | ||
|
|
||
| // hasPersistentConfig returns true if any config value that gets written to | ||
| // the config file was set. The setup key is excluded because it is only used | ||
| // for registration and is never persisted. | ||
| func (m *ManagedConfig) hasPersistentConfig() bool { | ||
| return m.managementURL != "" || | ||
| m.adminURL != "" || | ||
| m.preSharedKey != nil || | ||
| m.rosenpassEnabled != nil || | ||
| m.rosenpassPerm != nil || | ||
| m.disableAutoConn != nil | ||
| } | ||
|
|
||
| // Apply writes the MDM-managed configuration values to the config file at configPath. | ||
| // Values provided by MDM override any existing user-set values. | ||
| // The setup key is NOT written to the config file — it is used separately for registration. | ||
| func (m *ManagedConfig) Apply(configPath string) error { | ||
| if !m.hasPersistentConfig() { | ||
| return nil | ||
| } | ||
|
|
||
| log.Info("Applying MDM managed configuration") | ||
|
|
||
| input := profilemanager.ConfigInput{ | ||
| ConfigPath: configPath, | ||
| } | ||
|
|
||
| if m.managementURL != "" { | ||
| input.ManagementURL = m.managementURL | ||
| log.Info("MDM: setting management URL") | ||
| } | ||
|
|
||
| if m.adminURL != "" { | ||
| input.AdminURL = m.adminURL | ||
| log.Info("MDM: setting admin URL") | ||
| } | ||
|
|
||
| if m.preSharedKey != nil { | ||
| input.PreSharedKey = m.preSharedKey | ||
| log.Info("MDM: setting pre-shared key") | ||
| } | ||
|
|
||
| if m.rosenpassEnabled != nil { | ||
| input.RosenpassEnabled = m.rosenpassEnabled | ||
| log.Infof("MDM: setting Rosenpass enabled=%v", *m.rosenpassEnabled) | ||
| } | ||
|
|
||
| if m.rosenpassPerm != nil { | ||
| input.RosenpassPermissive = m.rosenpassPerm | ||
| log.Infof("MDM: setting Rosenpass permissive=%v", *m.rosenpassPerm) | ||
| } | ||
|
|
||
| if m.disableAutoConn != nil { | ||
| input.DisableAutoConnect = m.disableAutoConn | ||
| log.Infof("MDM: setting disable auto-connect=%v", *m.disableAutoConn) | ||
| } | ||
|
|
||
| _, err := profilemanager.UpdateOrCreateConfig(input) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to apply MDM config: %w", err) | ||
| } | ||
|
|
||
| log.Info("MDM managed configuration applied successfully") | ||
| return nil | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.