mdm: throw ErrNoSuchKey when a value not defined in Android syspolicy handler

Fixes tailscale/tailscale#11716

The implementation of the syspolicy handler on Android was incomplete. As explained in the comments (65f215115f/util/syspolicy/handler.go (L27)), a syspolicy handler should return a `syspolicy.ErrNoSuchKey` error when a value is not defined for a given key. The Android handler was instead returning an empty string.

When attempting to log in with a custom coordination server, since we were not returning syspolicy.ErrNoSuchKey, the caller into the syspolicy package (65f215115f/ipn/prefs.go (L665)) was always fetching an empty string from the MDM setting instead of using the default value `p.ControlURL`. Fallback logic would therefore always use the `DefaultControlURL` instead of the value defined in preferences.

Verified that upon specifying a custom coordination server in the app UI, a login screen for that coordination server appears and I can connect the Android device to that custom coordination server.

Signed-off-by: Andrea Gottardo <andrea@gottardo.me>
11716-android-beta-client-cannot-connect-to-alternate-self-hosted-headscale-server
Andrea Gottardo 2 weeks ago
parent 9533db44b7
commit 1428c54e6c

@ -453,17 +453,19 @@ class App : Application(), libtailscale.AppContext {
return downloads
}
@Throws(IOException::class, GeneralSecurityException::class)
@Throws(
IOException::class, GeneralSecurityException::class, MDMSettings.NoSuchKeyException::class)
override fun getSyspolicyBooleanValue(key: String): Boolean {
return getSyspolicyStringValue(key) == "true"
}
@Throws(IOException::class, GeneralSecurityException::class)
@Throws(
IOException::class, GeneralSecurityException::class, MDMSettings.NoSuchKeyException::class)
override fun getSyspolicyStringValue(key: String): String {
return MDMSettings.allSettingsByKey[key]?.flow?.value?.toString()
?: run {
Log.d("MDM", "$key is not defined on Android. Returning empty.")
""
Log.d("MDM", "$key is not defined on Android. Throwing NoSuchKeyException.")
throw MDMSettings.NoSuchKeyException()
}
}
}

@ -11,6 +11,11 @@ import kotlin.reflect.full.isSubclassOf
import kotlin.reflect.jvm.jvmErasure
object MDMSettings {
// The String message used in this NoSuchKeyException must match the value of
// syspolicy.ErrNoSuchKey defined in Go, since the backend checks the value
// returned by the handler for equality using errors.Is().
class NoSuchKeyException : Exception("no such key")
val forceEnabled = BooleanMDMSetting("ForceEnabled", "Force Enabled Connection Toggle")
val exitNodeID = StringMDMSetting("ExitNodeID", "Forced Exit Node: Stable ID")

Loading…
Cancel
Save