Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -261,6 +263,33 @@ public static ArrayList<Map.Entry<String, String>> 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();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return um.isManagedProfile();

if the device is fully managed, would this return false?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Talked to Mohit about this offline; the thinking is that for COBO devices, since they would constitute as a managed device (and not a managed profile), this method would return false. One Intune engineer also believes this is the case, but I will also check in with a different Intune team.
This question also prompted a renaming from isInWorkProfile to isInManagedProfile, to avoid any confusion as to what constitutes as a work profile.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
final DevicePolicyManager dpm = (DevicePolicyManager) appContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
final List<ComponentName> 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
Expand Down
Loading