Skip to content
Closed
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
4 changes: 3 additions & 1 deletion changelog.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
vNext
----------
- [MINOR] Add sovereign cloud (Bleu/Delos/SovSG) instance discovery support with pre-seeded cloud metadata, cache-aware discovery routing, and ensureCloudDiscoveryForAuthority API
- [PATCH] Fix bug in Authority.getKnownAuthorityResult where cloud discovery failure would skip knownAuthorities check
- [PATCH] Fix thread safety in Authority.isKnownAuthority and getEquivalentConfiguredAuthority with synchronized block
- [MINOR] Add AIDL interface for device registration service.(#2926)
- [MINOR] Move debugIntuneCE and prodIntuneCE from BrokerData to AppRegistry as App instances (#3012)
- [MINOR] Remove LruCache from SharedPreferencesFileManager (#2910)
- [MINOR] Edge TB: Claims (#2925)
- [PATCH] Update Moshi to 1.15.2 to resolve okio CVE-2023-3635 vulnerability (#3005)
- [MINOR] Edge TB: PoP support (#3006)
- [MINOR] Handle target="_blank" links in authorization WebView (#3010)
- [MINOR] Handle openid-vc urls in webview (#3013)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,18 +237,16 @@ Map<String, ADALTokenCacheItem> deserialize(final Map<String, String> tokenCache
public static boolean loadCloudDiscoveryMetadata() {
final String methodTag = TAG + ":loadCloudDiscoveryMetadata";

if (!AzureActiveDirectory.isInitialized()) {
try {
AzureActiveDirectory.performCloudDiscovery();
} catch (final ClientException e) {
Logger.error(
methodTag,
"Failed to load instance discovery metadata",
e
);
}
try {
AzureActiveDirectory.ensureCloudDiscoveryComplete();
return true;
} catch (final ClientException e) {
Logger.error(
methodTag,
"Failed to load instance discovery metadata",
e
);
return false;
}

return AzureActiveDirectory.isInitialized();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import static com.microsoft.identity.common.java.authscheme.BearerAuthenticationSchemeInternal.SCHEME_BEARER;
import static com.microsoft.identity.common.java.authscheme.PopAuthenticationSchemeInternal.SCHEME_POP;
import static com.microsoft.identity.common.java.authscheme.PopAuthenticationSchemeWithClientKeyInternal.SCHEME_POP_WITH_CLIENT_KEY;
import static com.microsoft.identity.common.java.authscheme.WebAppsPopAuthenticationSchemeInternal.SCHEME_POP_PREGENERATED;

import androidx.annotation.NonNull;

Expand All @@ -43,7 +42,6 @@
import com.microsoft.identity.common.java.authscheme.BearerAuthenticationSchemeInternal;
import com.microsoft.identity.common.java.authscheme.PopAuthenticationSchemeInternal;
import com.microsoft.identity.common.java.authscheme.PopAuthenticationSchemeWithClientKeyInternal;
import com.microsoft.identity.common.java.authscheme.WebAppsPopAuthenticationSchemeInternal;
import com.microsoft.identity.common.logging.Logger;

import java.lang.reflect.Type;
Expand Down Expand Up @@ -87,9 +85,6 @@ public AbstractAuthenticationScheme deserialize(@NonNull final JsonElement json,
case SCHEME_POP_WITH_CLIENT_KEY:
return context.deserialize(json, PopAuthenticationSchemeWithClientKeyInternal.class);

case SCHEME_POP_PREGENERATED:
return context.deserialize(json, WebAppsPopAuthenticationSchemeInternal.class);

default:
Logger.warn(
methodTag,
Expand All @@ -116,9 +111,6 @@ public JsonElement serialize(@NonNull final AbstractAuthenticationScheme src,
case SCHEME_POP_WITH_CLIENT_KEY:
return context.serialize(src, PopAuthenticationSchemeWithClientKeyInternal.class);

case SCHEME_POP_PREGENERATED:
return context.serialize(src, WebAppsPopAuthenticationSchemeInternal.class);

default:
Logger.warn(
methodTag,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,24 +232,19 @@ object SwitchBrowserUriHelper {
* @throws ClientException with error code [ClientException.MALFORMED_URL] if the URI string is malformed
* @throws ClientException with error code [ClientException.UNKNOWN_AUTHORITY] if the URI host is not a valid AAD authority
*
* @see AzureActiveDirectory.performCloudDiscovery
* @see AzureActiveDirectory.ensureCloudDiscoveryForAuthority
* @see AzureActiveDirectory.isValidCloudHost
*/
private fun validateActionUri(actionUriString: String) {
val methodTag = "$TAG:validateActionUri"
// Check if AzureActiveDirectory is initialized, if not, perform cloud discovery.
if (!AzureActiveDirectory.isInitialized()) {
Logger.warn(
methodTag,
"AzureActiveDirectory is not initialized. Performing cloud discovery."
)
try {
AzureActiveDirectory.performCloudDiscovery()
} catch (e: Exception) {
val errorMessage = "Failed to perform cloud discovery for AAD authorities."
Logger.error(methodTag, errorMessage, e)
throw ClientException(ClientException.IO_ERROR, errorMessage, e)
}
// Ensure cloud discovery is complete for this authority.
try {
val actionUrlForDiscovery = URL(actionUriString)
AzureActiveDirectory.ensureCloudDiscoveryForAuthority(actionUrlForDiscovery)
} catch (e: Exception) {
val errorMessage = "Failed to perform cloud discovery for AAD authorities."
Logger.error(methodTag, errorMessage, e)
throw ClientException(ClientException.IO_ERROR, errorMessage, e)
}
// Validate the action uri is not null or empty.
val actionUrl: URL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,9 +335,7 @@ private static String buildInteractiveGetTokenRequestJson(final boolean isSts) {
null,
false,
null,
null,
null, // tokenType
null // reqCnf
null
);

WebAppsGetTokenSubOperationEnvelope envelope = new WebAppsGetTokenSubOperationEnvelope(
Expand All @@ -363,9 +361,7 @@ private String buildStrictlySilentGetTokenRequestJson(final boolean isSts) throw
null, // loginHint
false, // instanceAware
null, // extraParameters
null, // claims
null, // tokenType
null // reqCnf
null // claims
);

WebAppsGetTokenSubOperationEnvelope envelope =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import com.microsoft.identity.common.java.authscheme.BearerAuthenticationSchemeInternal;
import com.microsoft.identity.common.java.authscheme.PopAuthenticationSchemeInternal;
import com.microsoft.identity.common.java.authscheme.PopAuthenticationSchemeWithClientKeyInternal;
import com.microsoft.identity.common.java.authscheme.WebAppsPopAuthenticationSchemeInternal;
import com.microsoft.identity.common.java.crypto.IDevicePopManager;

import org.junit.Assert;
Expand Down Expand Up @@ -77,17 +76,6 @@ public void testSerialize_PopAuthenticationSchemeWithClientKeyInternal() throws
Assert.assertEquals(expectedJson, json);
}

@Test
public void testSerialize_WebAppsPopAuthenticationSchemeInternal() throws MalformedURLException, IllegalArgumentException {
final String expectedJson =
"{\"req_cnf\":\"eyJraWQiOiJteS1rZXktaWQifQ\",\"kid\":\"my-key-id\",\"name\":\"PoP_Pregenerated\"}";
final WebAppsPopAuthenticationSchemeInternal scheme =
new WebAppsPopAuthenticationSchemeInternal("eyJraWQiOiJteS1rZXktaWQifQ");

final String json = AuthenticationSchemeTypeAdapter.getGsonInstance().toJson(scheme);
Assert.assertEquals(expectedJson, json);
}

@Test
public void testDeserialize_BearerAuthenticationSchemeInternal() {
final String json = "{\"name\":\"Bearer\"}";
Expand Down Expand Up @@ -115,14 +103,4 @@ public void testDeserialize_PopAuthenticationSchemeWithClientKeyInternal() {

Assert.assertTrue(authenticationScheme instanceof PopAuthenticationSchemeWithClientKeyInternal);
}

@Test
public void testDeserialize_WebAppsPopAuthenticationSchemeInternal() {
final String json =
"{\"http_method\":\"GET\",\"url\":\"https://xyz.com\",\"nonce\":\"nonce_test\",\"client_claims\":\"clientClaims_test\",\"req_cnf\":\"eyJraWQiOiJteS1rZXktaWQifQ\",\"name\":\"PoP_Pregenerated\"}";
final AbstractAuthenticationScheme authenticationScheme =
AuthenticationSchemeTypeAdapter.getGsonInstance().fromJson(json, AbstractAuthenticationScheme.class);

Assert.assertTrue(authenticationScheme instanceof WebAppsPopAuthenticationSchemeInternal);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -223,14 +223,16 @@ private static Authority getEquivalentConfiguredAuthority(@NonNull final String

// Iterate over all of the developer trusted authorities and check if the authorities
// are the same...
for (final Authority currentAuthority : knownAuthorities) {
if (!StringUtil.isNullOrEmpty(currentAuthority.mAuthorityUrlString)) {
final URL currentAuthorityUrl = new URL(currentAuthority.mAuthorityUrlString);
final String currentHttpAuthority = currentAuthorityUrl.getAuthority();

if (httpAuthority.equalsIgnoreCase(currentHttpAuthority)) {
result = currentAuthority;
break;
synchronized (sLock) {
for (final Authority currentAuthority : knownAuthorities) {
if (!StringUtil.isNullOrEmpty(currentAuthority.mAuthorityUrlString)) {
final URL currentAuthorityUrl = new URL(currentAuthority.mAuthorityUrlString);
final String currentHttpAuthority = currentAuthorityUrl.getAuthority();

if (httpAuthority.equalsIgnoreCase(currentHttpAuthority)) {
result = currentAuthority;
break;
}
}
}
}
Expand Down Expand Up @@ -309,22 +311,6 @@ public int hashCode() {
private static final List<Authority> knownAuthorities = new ArrayList<>();
private static final Object sLock = new Object();

private static void performCloudDiscovery()
throws ClientException {
final String methodName = ":performCloudDiscovery";
Logger.verbose(
TAG + methodName,
"Performing cloud discovery..."
);
synchronized (sLock) {
if (!AzureActiveDirectory.isInitialized()) {
Logger.verbose(TAG + methodName, "Not initialized. Starting request.");
AzureActiveDirectory.performCloudDiscovery();
Logger.info(TAG + methodName, "Loaded cloud metadata.");
}
}
}

public static void addKnownAuthorities(List<Authority> authorities) {
synchronized (sLock) {
knownAuthorities.addAll(authorities);
Expand Down Expand Up @@ -356,17 +342,19 @@ public static boolean isKnownAuthority(Authority authority) {
}

//Check if authority was added to configuration
for (final Authority currentAuthority : knownAuthorities) {
if (currentAuthority.mAuthorityUrlString != null &&
authority.getAuthorityURL() != null &&
authority.getAuthorityURL().getAuthority() != null &&
currentAuthority.mAuthorityUrlString.toLowerCase(Locale.ROOT).contains(
authority
.getAuthorityURL()
.getAuthority()
.toLowerCase(Locale.ROOT))) {
knownToDeveloper = true;
break;
synchronized (sLock) {
for (final Authority currentAuthority : knownAuthorities) {
if (currentAuthority.mAuthorityUrlString != null &&
authority.getAuthorityURL() != null &&
authority.getAuthorityURL().getAuthority() != null &&
currentAuthority.mAuthorityUrlString.toLowerCase(Locale.ROOT).contains(
authority
.getAuthorityURL()
.getAuthority()
.toLowerCase(Locale.ROOT))) {
knownToDeveloper = true;
break;
}
}
}

Expand Down Expand Up @@ -399,23 +387,26 @@ public static KnownAuthorityResult getKnownAuthorityResult(Authority authority)
boolean known = false;

try {
performCloudDiscovery();
AzureActiveDirectory.ensureCloudDiscoveryForAuthority(authority);
} catch (final ClientException ex) {
clientException = ex;
// Cloud discovery failed (e.g. network error).
// Log but continue — the authority may still be known via hardcoded
// metadata or developer configuration.
Logger.warn(TAG + methodName,
"Cloud discovery failed, will check hardcoded/configured authorities. Error: "
+ ex.getErrorCode());
}

Logger.info(TAG + methodName, "Cloud discovery complete.");

if (clientException == null) {
if (!isKnownAuthority(authority)) {
clientException = new ClientException(
ClientException.UNKNOWN_AUTHORITY,
"Provided authority is not known. MSAL will only make requests to known authorities"
);
} else {
Logger.info(TAG + methodName, "Cloud is known.");
known = true;
}
if (!isKnownAuthority(authority)) {
clientException = new ClientException(
ClientException.UNKNOWN_AUTHORITY,
"Provided authority is not known. MSAL will only make requests to known authorities"
);
} else {
Logger.info(TAG + methodName, "Cloud is known.");
known = true;
}

return new KnownAuthorityResult(known, clientException);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,8 @@ public OAuth2Strategy createOAuth2Strategy(@NonNull final OAuth2StrategyParamete
//@WorkerThread
public synchronized boolean isSameCloudAsAuthority(@NonNull final AzureActiveDirectoryAuthority authorityToCheck)
throws ClientException {
if (!AzureActiveDirectory.isInitialized()) {
// Cloud discovery is needed in order to make sure that we have a preferred_network_host_name to cloud aliases mappings
AzureActiveDirectory.performCloudDiscovery();
}
// Cloud discovery is needed to make sure that we have preferred_network_host_name to cloud aliases mappings
AzureActiveDirectory.ensureCloudDiscoveryForAuthority(this);

final AzureActiveDirectoryCloud cloudOfThisAuthority = getAzureActiveDirectoryCloud(mAudience);
final AzureActiveDirectoryCloud cloudOfAuthorityToCheck = getAzureActiveDirectoryCloud(authorityToCheck.getAudience());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ public static AbstractAuthenticationScheme createScheme(@NonNull final IPlatform
* @return boolean indicating if the the authentication scheme is a PoP authentication scheme
*/
public static boolean isPopAuthenticationScheme(@NonNull final AbstractAuthenticationScheme authenticationScheme) {
return authenticationScheme instanceof IPoPAuthenticationSchemeParams
|| authenticationScheme instanceof WebAppsPopAuthenticationSchemeInternal;
return authenticationScheme instanceof IPoPAuthenticationSchemeParams;
}
}
Loading
Loading