diff --git a/changelog.txt b/changelog.txt index 1106a8cc80..1afb155305 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,6 +7,7 @@ vNext - [MINOR] Add Child Spans for Interactive Span (#2516) - [MINOR] For MSAL CPP flows, match exact claims when deleting AT with intersecting scopes (#2548) - [MINOR] Replace Deprecated Keystore API for Android 28+ (#2558) +- [MINOR] Managed profile Android util method (#2561) - [PATCH] Make userHandle response field optional (#2560) Version 18.2.2 diff --git a/common/src/main/java/com/microsoft/identity/common/internal/fido/AuthFidoChallengeHandler.kt b/common/src/main/java/com/microsoft/identity/common/internal/fido/AuthFidoChallengeHandler.kt index 3e417bb527..832b5808c0 100644 --- a/common/src/main/java/com/microsoft/identity/common/internal/fido/AuthFidoChallengeHandler.kt +++ b/common/src/main/java/com/microsoft/identity/common/internal/fido/AuthFidoChallengeHandler.kt @@ -25,6 +25,7 @@ package com.microsoft.identity.common.internal.fido import android.webkit.WebView import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope +import com.microsoft.identity.common.internal.platform.AndroidPlatformUtil import com.microsoft.identity.common.internal.ui.webview.challengehandlers.IChallengeHandler import com.microsoft.identity.common.java.constants.FidoConstants import com.microsoft.identity.common.java.constants.FidoConstants.Companion.PASSKEY_PROTOCOL_ERROR_PREFIX_STRING @@ -66,7 +67,8 @@ class AuthFidoChallengeHandler ( span.setAttribute( AttributeName.fido_challenge_handler.name, TAG - ); + ) + Logger.info(methodTag, "Is app in work profile?: " + AndroidPlatformUtil.isInManagedProfile(webView.context)) // First verify submitUrl and context. Without these two, we can't respond back to the server. // If either one of these are missing or malformed, throw an exception and let the main WebViewClient handle it. val submitUrl = fidoChallenge.submitUrl.getOrThrow() diff --git a/common/src/main/java/com/microsoft/identity/common/internal/platform/AndroidPlatformUtil.java b/common/src/main/java/com/microsoft/identity/common/internal/platform/AndroidPlatformUtil.java index d5be29a5be..7f49212823 100644 --- a/common/src/main/java/com/microsoft/identity/common/internal/platform/AndroidPlatformUtil.java +++ b/common/src/main/java/com/microsoft/identity/common/internal/platform/AndroidPlatformUtil.java @@ -28,6 +28,7 @@ import android.app.Activity; import android.app.ActivityManager; +import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; @@ -37,6 +38,7 @@ import android.os.Handler; import android.os.Looper; import android.os.SystemClock; +import android.os.UserManager; import com.microsoft.identity.common.BuildConfig; import com.microsoft.identity.common.adal.internal.AuthenticationConstants; @@ -261,6 +263,33 @@ public static ArrayList> updateWithOrDeleteWebAuthnPar return result; } + /** + * Check if the host app is running within a managed profile. + * @param appContext current application context. + * @return true if app is in a managed profile, false if in personal profile or OS is below LOLLIPOP. + */ + public static boolean isInManagedProfile(@NonNull final Context appContext) { + // If the device is running on Android R or above, we can use the UserManager method isManagedProfile. + // Otherwise, if the device is running on Lollipop or above, we'll use DPM's isProfileOwnerApp. We return false for lower versions. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + final UserManager um = (UserManager) appContext.getSystemService(Context.USER_SERVICE); + return um.isManagedProfile(); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + final DevicePolicyManager dpm = (DevicePolicyManager) appContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + final List activeAdmins = dpm.getActiveAdmins(); + if (activeAdmins != null) { + // If any active admin apps are the profile owner, then the current calling app is in a managed profile. + for (final ComponentName admin : activeAdmins) { + final String packageName = admin.getPackageName(); + if (dpm.isProfileOwnerApp(packageName)) { + return true; + } + } + } + } + return false; + } + /** * This method optionally re-orders tasks to bring the task that launched * the interactive activity to the foreground. This is useful when the activity provided