Skip to content
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
e78eaf1
adjust lab stuff
fadidurah Feb 23, 2026
0386a4a
adjust ropc flow
fadidurah Feb 24, 2026
d651911
Merge branch 'dev' into fadi/lab-migrate
fadidurah Feb 24, 2026
00cd54e
add changes
fadidurah Feb 27, 2026
d012dc3
Merge branch 'fadi/lab-migrate' of https://github.com/AzureAD/microso…
fadidurah Feb 27, 2026
18dec8c
update apis
fadidurah Mar 3, 2026
5d10dfc
dev
fadidurah Mar 5, 2026
b4834ed
tweaks
fadidurah Mar 5, 2026
faa469c
update outlook
fadidurah Mar 11, 2026
342fd32
Merge branch 'dev' of https://github.com/AzureAD/microsoft-authentica…
fadidurah Mar 11, 2026
cbaa80a
adjustments
fadidurah Mar 12, 2026
387da03
Merge branch 'dev' of https://gitt pushhub.com/AzureAD/microsoft-auth…
fadidurah Mar 13, 2026
15418a4
Merge branch 'dev' of https://github.com/AzureAD/microsoft-authentica…
fadidurah Mar 16, 2026
9cb872e
update test code to get guest tenant
fadidurah Mar 16, 2026
ece5eda
Merge branch 'dev' into fadi/lab-migrate
fadidurah Mar 19, 2026
daf3769
Updating Common Lab API to be able to pass in new parameters correspo…
richardtz12 Mar 19, 2026
ff74ee0
merge dev
fadidurah Apr 23, 2026
17cd20c
dev
fadidurah Apr 27, 2026
cb08f3b
Fix ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD SpotBugs warning in LabCl…
Copilot Apr 27, 2026
a2f055a
add constant for easier maintenance
fadidurah Apr 29, 2026
3b91e38
ai comments
fadidurah Apr 29, 2026
b356c8e
ai comments
fadidurah Apr 29, 2026
1397c80
checks
fadidurah Apr 29, 2026
3d10e79
update outlook timeout
fadidurah May 1, 2026
e357416
update client to make it capable of calling oneauth upn json
fadidurah May 6, 2026
493e84f
update client to make it capable of calling oneauth upn json
fadidurah May 6, 2026
98b692a
update tests
fadidurah May 11, 2026
2ad2f2c
Merge branch 'dev' of https://github.com/AzureAD/microsoft-authentica…
fadidurah May 11, 2026
1062daf
checks
fadidurah May 11, 2026
3f21b46
Merge branch 'dev' of https://github.com/AzureAD/microsoft-atuthentic…
fadidurah May 13, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ public interface ILabAccount {
*/
String getHomeTenantId();

/**
* Get the guest tenant id of this account.
*
* @return a String representing the account's home tenant id
Comment thread
fadidurah marked this conversation as resolved.
Outdated
*/
String getGuestTenantId();
Comment thread
fadidurah marked this conversation as resolved.

/**
* Get the object id in home tenant.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public class LabAccount implements ILabAccount {
private final String mHomeObjectId;

private final String mAssociatedClientId;
private final String mGuestTenantId;

private final String mCloudUrl;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,39 @@ public class LabClient implements ILabClient {
private static final String ACCOUNT_UPN_JSON_STRING_SECRET_NAME = "Android-ID4SLAB2-User-Identifiers";
private Map<String, LabJsonStringAccountEntry> labUPNJsonMap = null;

Comment thread
fadidurah marked this conversation as resolved.
/**
* Holds the most recently fetched or created {@link ILabAccount} for this process.
Comment thread
fadidurah marked this conversation as resolved.
* <p>
* Updated after each successful account fetch or temporary user creation via
* {@link LabClient}. Intended as a convenience for single-threaded test scenarios
* that need access to the last lab account without explicitly passing it between
* methods.
* </p>
* <p>
* The field is {@code volatile} to ensure writes performed by one thread are
* immediately visible to all other threads. It may be {@code null} if no account
* has been fetched or created yet. Do not rely on this field in multi-threaded
* or production code.
* </p>
*/
public static volatile ILabAccount latestLabAccount = null;

/**
* Updates {@link #latestLabAccount} from a static context, avoiding the
* {@code ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD} SpotBugs warning that would
* be raised if instance methods assigned the field directly.
* <p>
* This method is thread-safe; the underlying field is {@code volatile}, so
* the write is immediately visible to all threads. {@code account} may be
* {@code null} to clear the stored account.
* </p>
*
* @param account The {@link ILabAccount} to store as the latest; may be {@code null}.
*/
private static void setLatestLabAccount(final ILabAccount account) {
latestLabAccount = account;
}

@Override
public ILabAccount getLabAccount(@NonNull final LabQuery labQuery) throws LabApiException {
// Adding a second attempt here, api sometimes fails to fetch the user.
Expand Down Expand Up @@ -142,7 +175,7 @@ private ILabAccount getLabAccountObject(@NonNull final ConfigInfo configInfo) th

final String password = getPassword(configInfo);

return new LabAccount.LabAccountBuilder()
final LabAccount account = new LabAccount.LabAccountBuilder()
.username(username)
.password(password)
.userType(UserType.fromName(configInfo.getUserInfo().getUserType()))
Expand All @@ -152,6 +185,10 @@ private ILabAccount getLabAccountObject(@NonNull final ConfigInfo configInfo) th
.cloudUrl(configInfo.getLabInfo().getAuthority())
.azureEnvironment(configInfo.getLabInfo().getAzureEnvironment())
.build();

setLatestLabAccount(account);

return account;
}

private List<ConfigInfo> fetchConfigsFromLab(@NonNull final String upn) throws LabApiException {
Expand Down Expand Up @@ -252,14 +289,17 @@ private ILabAccount createTempAccountInternal(@NonNull final TempUserType tempUs

final String password = getPassword(tempUser);

return new LabAccount.LabAccountBuilder()
final LabAccount account = new LabAccount.LabAccountBuilder()
.username(tempUser.getUpn())
.password(password)
// all temp users created by Lab Api are currently cloud users
.userType(UserType.CLOUD)
.homeTenantId(tempUser.getTenantId())
.homeObjectId(tempUser.getObjectId())
.build();

setLatestLabAccount(account);
return account;
}

@Override
Expand Down Expand Up @@ -356,16 +396,21 @@ public ILabAccount getAccountFromLabJsonStringInMobileBuildVault(UserType userTy
}
final String accountPassword = getPassword(accountEntry.getKeyVaultEntry());

return new LabAccount.LabAccountBuilder()
final LabAccount account = new LabAccount.LabAccountBuilder()
.username(accountEntry.getUpn())
.password(accountPassword)
.userType(userType)
.homeTenantId(accountEntry.getHomeTenantId())
.homeObjectId(accountEntry.getHomeObjectId())
.guestTenantId(accountEntry.getGuestTenantId())
.associatedClientId(accountEntry.getAssociatedClientId())
.azureEnvironment(accountEntry.getAzureEnvironment())
.cloudUrl(accountEntry.getCloudUrl())
.build();

setLatestLabAccount(account);

return account;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ public class LabJsonStringAccountEntry implements Serializable {
@SerializedName("HomeTenantId")
private String homeTenantId;

@SerializedName("GuestTenantId")
private String guestTenantId;

@SerializedName("AssociatedClientId")
private String associatedClientId;

@SerializedName("KeyVaultEntry")
private String keyVaultEntry;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,25 @@ public class LabConstants {
public static final String DEFAULT_LAB_SCOPE = "https://request.msidlab.com/.default";
public static final String KEYVAULT_SCOPE = "https://vault.azure.net/.default";
public static final String DEFAULT_LAB_CERT_ALIAS = "LabAuth.MSIDLab.com";
public static final String MSID_LAB3 = "https://login.microsoftonline.com/msidlab3.com";
public static final String MSID_LAB4 = "https://login.microsoftonline.com/msidlab4.com";
public static final String ID4SLAB2 = "https://login.microsoftonline.com/id4slab2.onmicrosoft.com";
public static final String ID4SLAB1 = "https://login.microsoftonline.com/id4slab1.onmicrosoft.com";

// TODO, REMOVE LEGACY UserTypes WHEN WE REMOVE LAB QUERY USAGE
static final class UserType {
public static final String BASIC = "basic";
public static final String MSA = "msa";
public static final String MDM_CA = "mdm_ca";
public static final String MAM_CA = "mam_ca";
public static final String MAM_ON_SPO = "mam_on_spo";
public static final String TP_CA = "tpca";
public static final String TRUE_MAM_CA = "true_mam_ca";
public static final String WP = "wp";
public static final String FEDERATED = "federated";
public static final String DEVICE_ADMIN = "device_admin";
public static final String USGOV = "usgov";
public static final String USGOV_GUEST = "usgov_guest";
public static final String CHINA = "china";
public static final String CHINA_GUEST = "china_guest";
public static final String QR_PIN = "qr_pin";
public static final String TOKEN_BINDING = "token_binding";
public static final String CBA = "cba";
Expand All @@ -62,6 +65,7 @@ static final class UserType {
public static final String ONPREM = "onprem";
public static final String GUEST = "guest";
public static final String B2C = "b2c";
public static final String CIAM = "ciam";
}

static final class UserRole {
Expand All @@ -86,6 +90,9 @@ static final class ProtectionPolicy {
public static final String TRUE_MAM_CA = "truemamca";
public static final String MAM_SPO = "mamspo";
public static final String BLOCKED = "blocked";
public static final String GLOBAL_MFA = "globalmfa";
public static final String AUTHAPP_LBAC = "authapplbac";
public static final String AUTHAPP_RICH_CONTEXT = "authapprichcontext";
}

static final class HomeDomain {
Expand Down Expand Up @@ -175,6 +182,8 @@ static final class TempUserType {
public static final String MFAONEXO = "MFAONEXO";
public static final String MAMCA = "MAMCA";
public static final String MDMCA = "MDMCA";
public static final String AUTHAPP_LBAC = "AuthappLBAC";
public static final String AUTHAPP_RICH_CONTEXT = "AuthappRichContext";
}

static final class TempUserPolicy {
Expand All @@ -183,6 +192,8 @@ static final class TempUserPolicy {
public static final String MFAONEXO = TempUserType.MFAONEXO;
public static final String MAMCA = TempUserType.MAMCA;
public static final String MDMCA = TempUserType.MDMCA;
public static final String AUTHAPP_LBAC = TempUserType.AUTHAPP_LBAC;
public static final String AUTHAPP_RICH_CONTEXT = TempUserType.AUTHAPP_RICH_CONTEXT;
}

static final class ResetOperation {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,15 @@ public enum ProtectionPolicy {
CA(LabConstants.ProtectionPolicy.CA),
CADJ(LabConstants.ProtectionPolicy.CADJ),
MAM(LabConstants.ProtectionPolicy.MAM),
GLOBAL_MFA(LabConstants.ProtectionPolicy.GLOBAL_MFA),
MDM(LabConstants.ProtectionPolicy.MDM),
MAM_CA(LabConstants.ProtectionPolicy.MAM_CA),
MDM_CA(LabConstants.ProtectionPolicy.MDM_CA),
TRUE_MAM_CA(LabConstants.ProtectionPolicy.TRUE_MAM_CA),
MAM_SPO(LabConstants.ProtectionPolicy.MAM_SPO),
BLOCKED(LabConstants.ProtectionPolicy.BLOCKED);
BLOCKED(LabConstants.ProtectionPolicy.BLOCKED),
AUTHAPP_LBAC(LabConstants.ProtectionPolicy.AUTHAPP_LBAC),
AUTHAPP_RICH_CONTEXT(LabConstants.ProtectionPolicy.AUTHAPP_RICH_CONTEXT);

final String value;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ public enum TempUserType {
MFA_ON_SPO(LabConstants.TempUserType.MFAONSPO),
MFA_ON_EXO(LabConstants.TempUserType.MFAONEXO),
MAM_CA(LabConstants.TempUserType.MAMCA),
MDM_CA(LabConstants.TempUserType.MDMCA);
MDM_CA(LabConstants.TempUserType.MDMCA),
AUTHAPP_LBAC(LabConstants.TempUserType.AUTHAPP_LBAC),
AUTHAPP_RICH_CONTEXT(LabConstants.TempUserType.AUTHAPP_RICH_CONTEXT);

final String value;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ public enum UserType {
MSA(LabConstants.UserType.MSA),
MDM_CA(LabConstants.UserType.MDM_CA),
MAM_CA(LabConstants.UserType.MAM_CA),
MAM_ON_SPO(LabConstants.UserType.MAM_ON_SPO),
TRUE_MAM_CA(LabConstants.UserType.TRUE_MAM_CA),
WP(LabConstants.UserType.WP),
FEDERATED(LabConstants.UserType.FEDERATED),
DEVICE_ADMIN(LabConstants.UserType.DEVICE_ADMIN),
USGOV(LabConstants.UserType.USGOV),
USGOV_GUEST(LabConstants.UserType.USGOV_GUEST),
CHINA(LabConstants.UserType.CHINA),
CHINA_GUEST(LabConstants.UserType.CHINA_GUEST),
QR_PIN(LabConstants.UserType.QR_PIN),
TOKEN_BINDING(LabConstants.UserType.TOKEN_BINDING),
CBA(LabConstants.UserType.CBA),
Expand All @@ -51,6 +53,7 @@ public enum UserType {
DUNA_MFA_2(LabConstants.UserType.DUNA_MFA_2),
CLOUD(LabConstants.UserType.CLOUD),
B2C(LabConstants.UserType.B2C),
CIAM(LabConstants.UserType.CIAM),
GUEST(LabConstants.UserType.GUEST),
ONPREM(LabConstants.UserType.ONPREM);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ public class LabClientTest {
@Rule
public RetryTestRule retryRule = new RetryTestRule(3);

private final String DEFAULT_LAB_NAME = "id4slab2";
private final String GUEST_LAB_NAME = "id4slab1";

@Before
public void setup() {
final LabApiAuthenticationClient authenticationClient = new LabApiAuthenticationClient(
Expand All @@ -68,26 +71,18 @@ public void cleanup() {

@Test
public void canFetchCloudAccount() {
Comment thread
fadidurah marked this conversation as resolved.
Outdated
final LabQuery query = LabQuery.builder()
.userType(UserType.CLOUD)
.build();

try {
final ILabAccount labAccount = mLabClient.getLabAccount(query);
assertLabAccount(labAccount, UserType.CLOUD, "msidlab4");
final ILabAccount labAccount = mLabClient.getAccountFromLabJsonStringInMobileBuildVault(UserType.BASIC);
assertLabAccount(labAccount, UserType.BASIC, DEFAULT_LAB_NAME);
} catch (final LabApiException e) {
throw new AssertionError(e);
}
}

@Test
public void canFetchMSAAccount() {
final LabQuery query = LabQuery.builder()
.userType(UserType.MSA)
.build();

try {
final ILabAccount labAccount = mLabClient.getLabAccount(query);
final ILabAccount labAccount = mLabClient.getAccountFromLabJsonStringInMobileBuildVault(UserType.MSA);
assertLabAccount(labAccount, UserType.MSA, "outlook");
} catch (final LabApiException e) {
throw new AssertionError(e);
Expand All @@ -96,27 +91,41 @@ public void canFetchMSAAccount() {

@Test
public void canFetchGuestAccount() {
final LabQuery query = LabQuery.builder()
.userType(UserType.GUEST)
.build();

try {
final ILabAccount labAccount = mLabClient.getLabAccount(query);
assertLabAccount(labAccount, UserType.GUEST, "msidlab4");
final ILabAccount labAccount = mLabClient.getAccountFromLabJsonStringInMobileBuildVault(UserType.GUEST);
assertLabAccount(labAccount, UserType.GUEST, GUEST_LAB_NAME);
} catch (final LabApiException e) {
throw new AssertionError(e);
}
}

@Test
public void canFetchFederatedAccount() {
final LabQuery query = LabQuery.builder()
.userType(UserType.FEDERATED)
.build();
try {
final ILabAccount labAccount = mLabClient.getAccountFromLabJsonStringInMobileBuildVault(UserType.FEDERATED);
assertLabAccount(labAccount, UserType.FEDERATED, DEFAULT_LAB_NAME);
} catch (final LabApiException e) {
throw new AssertionError(e);
}
}

@Test
public void canFetchUsGovAccount() {
try {
final ILabAccount labAccount = mLabClient.getAccountFromLabJsonStringInMobileBuildVault(UserType.USGOV);

assertLabAccount(labAccount, null, "arlmsidlab1");
} catch (final LabApiException e) {
Comment thread
fadidurah marked this conversation as resolved.
throw new AssertionError(e);
}
}

@Test
public void canFetchChinaAccount() {
try {
final ILabAccount labAccount = mLabClient.getLabAccount(query);
assertLabAccount(labAccount, UserType.FEDERATED, "msidlab4");
final ILabAccount labAccount = mLabClient.getAccountFromLabJsonStringInMobileBuildVault(UserType.CHINA);

assertLabAccount(labAccount, null, "mncmsidlab1");
} catch (final LabApiException e) {
Comment thread
fadidurah marked this conversation as resolved.
throw new AssertionError(e);
}
Expand All @@ -126,7 +135,7 @@ public void canFetchFederatedAccount() {
public void canCreateBasicTempUser() {
try {
final ILabAccount labAccount = mLabClient.createTempAccount(TempUserType.BASIC);
assertLabAccount(labAccount, UserType.CLOUD, "msidlab4");
assertLabAccount(labAccount, UserType.CLOUD, DEFAULT_LAB_NAME);
} catch (final LabApiException e) {
throw new AssertionError(e);
}
Expand All @@ -136,7 +145,7 @@ public void canCreateBasicTempUser() {
public void canCreateMAMCATempUser() {
try {
final ILabAccount labAccount = mLabClient.createTempAccount(TempUserType.MAM_CA);
assertLabAccount(labAccount, UserType.CLOUD, "msidlab4");
assertLabAccount(labAccount, UserType.CLOUD, DEFAULT_LAB_NAME);
} catch (final LabApiException e) {
throw new AssertionError(e);
}
Expand Down Expand Up @@ -186,25 +195,11 @@ public void canFetchPasswordFromKeyVault() {
}

@Test
public void canFetchAccountUpnJsonString() {
public void canFetchAccountUpnJsonStringOtherAccounts() {
try {
final Map<String, LabJsonStringAccountEntry> accountUpnMap = mLabClient.getAccountMapJsonFromMobileBuildKeyVault();
Assert.assertTrue(accountUpnMap != null && !accountUpnMap.isEmpty());

final ILabAccount basicUser = mLabClient.getAccountFromLabJsonStringInMobileBuildVault(UserType.BASIC);
Assert.assertNotNull(basicUser);
Assert.assertNotNull(basicUser.getUsername());
Assert.assertNotNull(basicUser.getPassword());
Assert.assertNotNull(basicUser.getHomeObjectId());
Assert.assertNotNull(basicUser.getHomeTenantId());

final ILabAccount msaUser = mLabClient.getAccountFromLabJsonStringInMobileBuildVault(UserType.MSA);
Assert.assertNotNull(msaUser);
Assert.assertNotNull(msaUser.getUsername());
Assert.assertNotNull(msaUser.getPassword());
Assert.assertNotNull(msaUser.getHomeObjectId());
Assert.assertNotNull(msaUser.getHomeTenantId());

final ILabAccount resourceAccount = mLabClient.getAccountFromLabJsonStringInMobileBuildVault(UserType.RESOURCE_ACCOUNT_1);
Assert.assertNotNull(resourceAccount);
Assert.assertNotNull(resourceAccount.getUsername());
Expand Down
Loading
Loading