Skip to content

Commit 9f67d10

Browse files
author
Mohit Chandwani
committed
Merge branch 'dev' into mchand/keystore-unwrap-fix
2 parents 72cd7cd + a05fa64 commit 9f67d10

17 files changed

Lines changed: 453 additions & 33 deletions

File tree

azure-pipelines/pull-request-validation/common.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Variable: 'MOCK_API_URL' was defined in the Variables tab
33
# Description: Assemble and run unit test
44
name: $(date:yyyyMMdd)$(rev:.r)
5-
5+
trigger: none
66
variables:
77
- group: devex-ciam-test
88

azure-pipelines/pull-request-validation/common4j.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# Variable: 'MOCK_API_URL' was defined in the Variables tab
44
# Uses Java 11
55
name: $(date:yyyyMMdd)$(rev:.r)
6-
6+
trigger: none
77
variables:
88
- group: devex-ciam-test
99

changelog.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
vNext
22
----------
33
- [PATCH] Allow generating wrapping keys without PURPOSE_WRAP_KEY with Flight (#2633))
4+
- [MINOR] Pass Work Profile existence, OS Version, and Manufacturer to ESTS (#2627)
45
- [MINOR] Add telemetry for the switch browser protocol (#2612)
5-
- [MINOR] Enable the new Broker discovery on MSAL by default (#2618)
66

77
Version 21.0.0
88
----------

common/src/main/java/com/microsoft/identity/common/adal/internal/AuthenticationConstants.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,18 @@ public static String computeMaxHostBrokerProtocol() {
11611161
*/
11621162
public static final String LTW_APP_SHA512_DEBUG_SIGNATURE = "5PAhhZNSRRvq7vpTT5vrYJbSLh05AU8USf7oUTS239PEltebX87uGN7GhAe5244lJepwZ5RU4vu8N6ospXVOlg==";
11631163

1164+
/**
1165+
* Signing certificate thumbprint of the DEBUG-signed Microsoft Intune app.
1166+
* Generated with SHA-512.
1167+
*/
1168+
public static final String INTUNE_APP_SHA512_DEBUG_SIGNATURE = "F+Tat7A/mlOJCzRYEmj9DgLRHU2Nb0VSQjgZEyAehqW9+cOT0oYjkT/fa33hYcVMwUzaSy0hUOVt9KQtyFRnVQ==";
1169+
1170+
/**
1171+
* Signing certificate thumbprint of the RELEASE-signed Microsoft Intune app.
1172+
* Generated with SHA-512.
1173+
*/
1174+
public static final String INTUNE_APP_SHA512_RELEASE_SIGNATURE = "jPpMoaNvcxSLMX4yG4C3Gf86rtTqh33SqpuRKg4WOP+MnnpA52zZgvKLW76U4Cqqf68iaBk9W7k/jhciiSAtgQ==";
1175+
11641176
/**
11651177
* Teams IP Phones (Sakurai devices) is supported by Intune, but does not have a back button nor browser.
11661178
* The only supported detection of this phone is the application install state.

common/src/main/java/com/microsoft/identity/common/components/AndroidPlatformComponentsFactory.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.microsoft.identity.common.internal.providers.oauth2.AndroidTaskStateGenerator;
3737
import com.microsoft.identity.common.internal.ui.AndroidAuthorizationStrategyFactory;
3838
import com.microsoft.identity.common.internal.ui.browser.AndroidBrowserSelector;
39+
import com.microsoft.identity.common.internal.util.WorkProfileUtil;
3940
import com.microsoft.identity.common.java.WarningType;
4041
import com.microsoft.identity.common.java.interfaces.IPlatformComponents;
4142
import com.microsoft.identity.common.java.interfaces.PlatformComponents;
@@ -67,6 +68,10 @@ public static synchronized void initializeGlobalStates(@NonNull final Context co
6768
if (!sGlobalStateInitalized) {
6869
HttpCache.initialize(context);
6970
Device.setDeviceMetadata(new AndroidDeviceMetadata());
71+
72+
// Denotes whether or not request is from personal profile but device has a Work Profile Available
73+
Device.setIsInPersonalProfileButClouddpcWorkProfileAvailable(
74+
WorkProfileUtil.checkIfIsInPersonalProfileButClouddpcWorkProfileAvailable(context));
7075
Logger.setAndroidLogger();
7176

7277
final File cacheDir = context.getCacheDir();

common/src/main/java/com/microsoft/identity/common/internal/activebrokerdiscovery/BrokerDiscoveryClient.kt

Lines changed: 119 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,30 @@ class BrokerDiscoveryClient(private val brokerCandidates: Set<BrokerData>,
7373
val dispatcher = Dispatchers.IO.limitedParallelism(10)
7474

7575
const val ACTIVE_BROKER_PACKAGE_NAME_BUNDLE_KEY = "ACTIVE_BROKER_PACKAGE_NAME_BUNDLE_KEY"
76-
const val ACTIVE_BROKER_SIGNING_CERTIFICATE_THUMBPRINT_BUNDLE_KEY = "ACTIVE_BROKER_SIGNING_CERTIFICATE_THUMBPRINT_BUNDLE_KEY"
76+
const val ACTIVE_BROKER_SIGNING_CERTIFICATE_THUMBPRINT_BUNDLE_KEY =
77+
"ACTIVE_BROKER_SIGNING_CERTIFICATE_THUMBPRINT_BUNDLE_KEY"
78+
79+
const val FORCE_TRIGGER_BROKER_DISCOVERY_BUNDLE_KEY =
80+
"FORCE_TRIGGER_BROKER_DISCOVERY_BUNDLE_KEY"
81+
const val FORCE_TRIGGER_BROKER_DISCOVERY_RESULT_EXECUTED_BUNDLE_KEY =
82+
"FORCE_TRIGGER_BROKER_DISCOVERY_RESULT_EXECUTED_BUNDLE_KEY"
83+
84+
// the broker service is too old and doesn't support this API.
85+
const val FORCE_TRIGGER_BROKER_DISCOVERY_RESULT_OPERATION_NOT_SUPPORTED =
86+
"OPERATION_NOT_SUPPORTED"
87+
88+
// the broker service recognizes this API, but the feature is disabled (e.g. behind a flight).
89+
const val FORCE_TRIGGER_BROKER_DISCOVERY_RESULT_OPERATION_DISABLED = "OPERATION_DISABLED"
90+
91+
// the broker app you're communicating to is not installed.
92+
const val FORCE_TRIGGER_BROKER_DISCOVERY_PACKAGE_NOT_INSTALLED = "PACKAGE_NOT_INSTALLED"
93+
94+
// the broker service you're communicating to is not a valid broker app. (e.g. not signed by proper keys)
95+
const val FORCE_TRIGGER_BROKER_DISCOVERY_NOT_VALID_BROKER = "NOT_VALID_BROKER"
96+
97+
// Unexpected error.
98+
const val FORCE_TRIGGER_BROKER_DISCOVERY_RESULT_UNEXPECTED_ERROR = "UNEXPECTED_ERROR"
99+
77100
const val ERROR_BUNDLE_KEY = "ERROR_BUNDLE_KEY"
78101

79102
/**
@@ -93,13 +116,15 @@ class BrokerDiscoveryClient(private val brokerCandidates: Set<BrokerData>,
93116
* @param shouldStopQueryForAWhile a method which, if invoked, will force [BrokerDiscoveryClient]
94117
* to skip the IPC discovery process for a while.
95118
**/
96-
internal suspend fun queryFromBroker(brokerCandidates: Set<BrokerData>,
97-
ipcStrategy: IIpcStrategy,
98-
isPackageInstalled: (BrokerData) -> Boolean,
99-
isValidBroker: (BrokerData) -> Boolean
119+
internal suspend fun queryFromBroker(
120+
brokerCandidates: Set<BrokerData>,
121+
ipcStrategy: IIpcStrategy,
122+
isPackageInstalled: (BrokerData) -> Boolean,
123+
isValidBroker: (BrokerData) -> Boolean
100124
): BrokerData? {
101125
return coroutineScope {
102-
val installedCandidates = brokerCandidates.filter(isPackageInstalled).filter(isValidBroker)
126+
val installedCandidates =
127+
brokerCandidates.filter(isPackageInstalled).filter(isValidBroker)
103128
val deferredResults = installedCandidates.map { candidate ->
104129
async(dispatcher) {
105130
return@async makeRequest(candidate, ipcStrategy)
@@ -109,8 +134,10 @@ class BrokerDiscoveryClient(private val brokerCandidates: Set<BrokerData>,
109134
}
110135
}
111136

112-
private fun makeRequest(candidate: BrokerData,
113-
ipcStrategy: IIpcStrategy): BrokerData? {
137+
private fun makeRequest(
138+
candidate: BrokerData,
139+
ipcStrategy: IIpcStrategy
140+
): BrokerData? {
114141
val methodTag = "$TAG:makeRequest"
115142
val operationBundle = BrokerOperationBundle(
116143
BrokerOperationBundle.Operation.BROKER_DISCOVERY_FROM_SDK,
@@ -120,19 +147,26 @@ class BrokerDiscoveryClient(private val brokerCandidates: Set<BrokerData>,
120147

121148
return try {
122149
val result = ipcStrategy.communicateToBroker(operationBundle)
123-
extractResult(result)
150+
extractResult(result, forceTriggerDiscoveryFlow = false)
124151
} catch (t: Throwable) {
125152
if (t is BrokerCommunicationException &&
126-
BrokerCommunicationException.Category.OPERATION_NOT_SUPPORTED_ON_SERVER_SIDE == t.category) {
127-
Logger.info(methodTag,
128-
"Tried broker discovery on ${candidate}. It doesn't support the IPC mechanism.")
129-
} else if (t is ClientException && ONLY_SUPPORTS_ACCOUNT_MANAGER_ERROR_CODE == t.errorCode){
130-
Logger.info(methodTag,
153+
BrokerCommunicationException.Category.OPERATION_NOT_SUPPORTED_ON_SERVER_SIDE == t.category
154+
) {
155+
Logger.info(
156+
methodTag,
157+
"Tried broker discovery on ${candidate}. It doesn't support the IPC mechanism."
158+
)
159+
} else if (t is ClientException && ONLY_SUPPORTS_ACCOUNT_MANAGER_ERROR_CODE == t.errorCode) {
160+
Logger.info(
161+
methodTag,
131162
"Tried broker discovery on ${candidate}. " +
132-
"The Broker side indicates that only AccountManager is supported.")
163+
"The Broker side indicates that only AccountManager is supported."
164+
)
133165
} else {
134-
Logger.error(methodTag,
135-
"Tried broker discovery on ${candidate}, get an error", t)
166+
Logger.error(
167+
methodTag,
168+
"Tried broker discovery on ${candidate}, get an error", t
169+
)
136170
}
137171
null
138172
}
@@ -142,7 +176,8 @@ class BrokerDiscoveryClient(private val brokerCandidates: Set<BrokerData>,
142176
* Extract the result returned via the IPC operation
143177
**/
144178
@Throws(NoSuchElementException::class)
145-
private fun extractResult(bundle: Bundle?): BrokerData? {
179+
private fun extractResult(bundle: Bundle?,
180+
forceTriggerDiscoveryFlow: Boolean): BrokerData? {
146181
if (bundle == null) {
147182
return null
148183
}
@@ -152,33 +187,92 @@ class BrokerDiscoveryClient(private val brokerCandidates: Set<BrokerData>,
152187
throw errorData as Throwable
153188
}
154189

155-
val pkgName = bundle.getString(ACTIVE_BROKER_PACKAGE_NAME_BUNDLE_KEY)?:
156-
throw NoSuchElementException("ACTIVE_BROKER_PACKAGE_NAME_BUNDLE_KEY must not be null")
190+
if (forceTriggerDiscoveryFlow &&
191+
!bundle.containsKey(FORCE_TRIGGER_BROKER_DISCOVERY_RESULT_EXECUTED_BUNDLE_KEY)) {
192+
throw ClientException(
193+
FORCE_TRIGGER_BROKER_DISCOVERY_RESULT_OPERATION_NOT_SUPPORTED,
194+
"Force Broker Discovery is not supported by the broker side. Please update the app."
195+
)
196+
}
197+
198+
val pkgName = bundle.getString(ACTIVE_BROKER_PACKAGE_NAME_BUNDLE_KEY)
199+
?: throw NoSuchElementException("ACTIVE_BROKER_PACKAGE_NAME_BUNDLE_KEY must not be null")
157200

158-
val signatureHash = bundle.getString(ACTIVE_BROKER_SIGNING_CERTIFICATE_THUMBPRINT_BUNDLE_KEY)?:
159-
throw NoSuchElementException("ACTIVE_BROKER_SIGNING_CERTIFICATE_THUMBPRINT_BUNDLE_KEY must not be null")
201+
val signatureHash =
202+
bundle.getString(ACTIVE_BROKER_SIGNING_CERTIFICATE_THUMBPRINT_BUNDLE_KEY)
203+
?: throw NoSuchElementException("ACTIVE_BROKER_SIGNING_CERTIFICATE_THUMBPRINT_BUNDLE_KEY must not be null")
160204

161205
return BrokerData(pkgName, signatureHash)
162206
}
163207
}
164208

165209
constructor(context: Context,
166210
components: IPlatformComponents,
167-
cache: IClientActiveBrokerCache): this(
211+
cache: IClientActiveBrokerCache) : this(
168212
brokerCandidates = BrokerData.getKnownBrokerApps(),
169213
getActiveBrokerFromAccountManager = {
170214
AccountManagerBrokerDiscoveryUtil(context).getActiveBrokerFromAccountManager()
171215
},
172216
ipcStrategy = ContentProviderStrategy(context, components),
173217
cache = cache,
174218
isPackageInstalled = { brokerData ->
175-
PackageHelper(context).
176-
isPackageInstalledAndEnabled(brokerData.packageName)
219+
PackageHelper(context).isPackageInstalledAndEnabled(brokerData.packageName)
177220
},
178221
isValidBroker = { brokerData ->
179222
BrokerValidator(context).isSignedByKnownKeys(brokerData)
180223
})
181224

225+
@kotlin.jvm.Throws(ClientException::class)
226+
override fun forceBrokerRediscovery(brokerCandidate: BrokerData): BrokerData {
227+
val methodTag = "$TAG:forceBrokerRediscovery"
228+
return runBlocking {
229+
classLevelLock.withLock {
230+
try {
231+
if (!isPackageInstalled(brokerCandidate)) {
232+
throw ClientException(
233+
FORCE_TRIGGER_BROKER_DISCOVERY_PACKAGE_NOT_INSTALLED,
234+
"${brokerCandidate.packageName} is not installed."
235+
)
236+
}
237+
238+
if (!isValidBroker(brokerCandidate)) {
239+
throw ClientException(
240+
FORCE_TRIGGER_BROKER_DISCOVERY_NOT_VALID_BROKER,
241+
"${brokerCandidate.packageName} is not signed with valid key."
242+
)
243+
}
244+
245+
val operationBundle = BrokerOperationBundle(
246+
BrokerOperationBundle.Operation.BROKER_DISCOVERY_FROM_SDK,
247+
brokerCandidate.packageName,
248+
Bundle().apply {
249+
putBoolean(FORCE_TRIGGER_BROKER_DISCOVERY_BUNDLE_KEY, true)
250+
}
251+
)
252+
253+
val bundleResult = ipcStrategy.communicateToBroker(operationBundle)
254+
val result = extractResult(bundleResult, forceTriggerDiscoveryFlow = true)
255+
?: throw ClientException(
256+
FORCE_TRIGGER_BROKER_DISCOVERY_RESULT_UNEXPECTED_ERROR,
257+
"Result bundle should not be null."
258+
)
259+
cache.setCachedActiveBroker(result)
260+
return@runBlocking result
261+
} catch (c: ClientException) {
262+
Logger.error(methodTag, "forceBrokerRediscovery Failed.", c)
263+
throw c
264+
} catch (t: Throwable) {
265+
Logger.error(methodTag, "forceBrokerRediscovery Failed with unknown error.", t)
266+
throw ClientException(
267+
FORCE_TRIGGER_BROKER_DISCOVERY_RESULT_UNEXPECTED_ERROR,
268+
"Unexpected result: ${t.message}",
269+
t
270+
)
271+
}
272+
}
273+
}
274+
}
275+
182276
override fun getActiveBroker(shouldSkipCache: Boolean): BrokerData? {
183277
return runBlocking {
184278
return@runBlocking getActiveBrokerAsync(shouldSkipCache)

common/src/main/java/com/microsoft/identity/common/internal/activebrokerdiscovery/BrokerDiscoveryClientFactory.kt

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ class BrokerDiscoveryClientFactory {
3939

4040
companion object {
4141

42+
private val TAG = BrokerDiscoveryClientFactory::class.simpleName
43+
44+
@Volatile
45+
private var IS_NEW_DISCOVERY_ENABLED = false
46+
4247
@Volatile
4348
private var clientSdkInstance: IBrokerDiscoveryClient? = null
4449

@@ -56,15 +61,20 @@ class BrokerDiscoveryClientFactory {
5661
**/
5762
@JvmStatic
5863
fun setNewBrokerDiscoveryEnabled(isEnabled: Boolean){
59-
// noop
64+
// If the flag changes, wipe the existing singleton.
65+
if (isEnabled != IS_NEW_DISCOVERY_ENABLED) {
66+
clientSdkInstance = null
67+
brokerSdkInstance = null
68+
IS_NEW_DISCOVERY_ENABLED = isEnabled
69+
}
6070
}
6171

6272
/**
6373
* Returns true if the new Broker discovery mechanism is enabled.
6474
**/
6575
@JvmStatic
6676
fun isNewBrokerDiscoveryEnabled(): Boolean {
67-
return true;
77+
return BuildConfig.newBrokerDiscoveryEnabledFlag || IS_NEW_DISCOVERY_ENABLED;
6878
}
6979

7080
/**
@@ -116,7 +126,14 @@ class BrokerDiscoveryClientFactory {
116126
private fun getInstance(context: Context,
117127
platformComponents: IPlatformComponents,
118128
cache: IClientActiveBrokerCache) : IBrokerDiscoveryClient{
119-
return BrokerDiscoveryClient(context, platformComponents, cache)
129+
val methodTag = "$TAG:getInstance"
130+
return if (isNewBrokerDiscoveryEnabled()) {
131+
Logger.info(methodTag, "Broker Discovery is enabled. Use the new logic on the SDK side")
132+
BrokerDiscoveryClient(context, platformComponents, cache)
133+
} else {
134+
Logger.info(methodTag, "Broker Discovery is disabled. Use AccountManager on the SDK side.")
135+
LegacyBrokerDiscoveryClient(context)
136+
}
120137
}
121138
}
122139
}

common/src/main/java/com/microsoft/identity/common/internal/activebrokerdiscovery/IBrokerDiscoveryClient.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
package com.microsoft.identity.common.internal.activebrokerdiscovery
2424

2525
import com.microsoft.identity.common.internal.broker.BrokerData
26+
import com.microsoft.identity.common.java.exception.ClientException
2627

2728
interface IBrokerDiscoveryClient {
2829

@@ -35,4 +36,19 @@ interface IBrokerDiscoveryClient {
3536
* @return BrokerData package name and signature hash of the targeted app.
3637
* **/
3738
fun getActiveBroker(shouldSkipCache: Boolean = false) : BrokerData?
39+
40+
/**
41+
* Force a broker app to figure out which broker app the SDK (MSAL/OneAuth)
42+
* has to send its request to.
43+
*
44+
* This method will ignore the cache values on both SDK and broker side.
45+
*
46+
* Due to the nature of the method, the Android broker team will limit which app can invoke this method,
47+
* and what circumstance it's allowed to do so (e.g. flight enabled for a certain tenant only).
48+
* Please consult the Android broker team before use.
49+
*
50+
* @return BrokerData package name and signature hash of the targeted app.
51+
* **/
52+
@kotlin.jvm.Throws(ClientException::class)
53+
fun forceBrokerRediscovery(brokerCandidate: BrokerData): BrokerData
3854
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// All rights reserved.
3+
//
4+
// This code is licensed under the MIT License.
5+
//
6+
// Permission is hereby granted, free of charge, to any person obtaining a copy
7+
// of this software and associated documentation files(the "Software"), to deal
8+
// in the Software without restriction, including without limitation the rights
9+
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
10+
// copies of the Software, and to permit persons to whom the Software is
11+
// furnished to do so, subject to the following conditions :
12+
//
13+
// The above copyright notice and this permission notice shall be included in
14+
// all copies or substantial portions of the Software.
15+
//
16+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
// THE SOFTWARE.
23+
package com.microsoft.identity.common.internal.activebrokerdiscovery
24+
25+
import android.content.Context
26+
import com.microsoft.identity.common.internal.broker.BrokerData
27+
28+
/**
29+
* An [IBrokerDiscoveryClient] which is based on AccountManager.
30+
**/
31+
class LegacyBrokerDiscoveryClient(val context: Context): IBrokerDiscoveryClient {
32+
33+
override fun getActiveBroker(shouldSkipCache: Boolean): BrokerData? {
34+
return AccountManagerBrokerDiscoveryUtil(context)
35+
.getActiveBrokerFromAccountManager()
36+
}
37+
38+
override fun forceBrokerRediscovery(brokerCandidate: BrokerData): BrokerData {
39+
throw UnsupportedOperationException("LegacyBrokerDiscoveryClient does not support forceBrokerRediscovery.")
40+
}
41+
}

0 commit comments

Comments
 (0)