Skip to content

Commit 1ff8a90

Browse files
committed
resource account api
1 parent ab89925 commit 1ff8a90

11 files changed

Lines changed: 458 additions & 9 deletions

File tree

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1610,7 +1610,8 @@ public enum API {
16101610
BROKER_RESTORE_MSA_ACCOUNTS_WITH_TRANSFER_TOKENS(BROKER_RESTORE_MSA_ACCOUNTS_WITH_TRANSFER_TOKENS_PATH, BROKER_VERSION_5, null),
16111611

16121612
WEBAPPS_GET_SUPPORTED_WEB_APPS_CONTRACTS(WEBAPPS_GET_SUPPORTED_WEB_APPS_CONTRACTS_PATH, null, null),
1613-
WEBAPPS_EXECUTE_WEB_APPS_REQUEST(WEBAPPS_EXECUTE_WEB_APPS_REQUEST_PATH, null, null);
1613+
WEBAPPS_EXECUTE_WEB_APPS_REQUEST(WEBAPPS_EXECUTE_WEB_APPS_REQUEST_PATH, null, null),
1614+
PROVISION_RESOURCE_ACCOUNT(PROVISION_RESOURCE_ACCOUNT_PATH, null, null); // TODO: add broker version
16141615

16151616
/**
16161617
* The content provider path that the API exists behind.
@@ -1789,6 +1790,11 @@ public String getMsalVersion(){
17891790
*/
17901791
public static final String WEBAPPS_EXECUTE_WEB_APPS_REQUEST_PATH = "/webapp/executeWebAppsRequest";
17911792

1793+
1794+
public static final String PROVISION_RESOURCE_ACCOUNT_PATH = "/provisionResourceAccount";
1795+
1796+
public static final String GET_AAD_DEVICE_ID_PATH = "/getAadDeviceId";
1797+
17921798
/**
17931799
* BrokerContentProvider URI code constant for MSAL-to-Broker hello request.
17941800
*/

common/src/main/java/com/microsoft/identity/common/internal/broker/BrokerRequest.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,21 +94,18 @@ private static final class SerializedNames {
9494
* Scopes for the request. This is expected to be of the format
9595
* "scope 1 scope2 scope3" with space as a delimiter
9696
*/
97-
@NonNull
9897
@SerializedName(SerializedNames.SCOPE)
9998
private String mScope;
10099

101100
/**
102101
* The redirect uri for the request.
103102
*/
104-
@NonNull
105103
@SerializedName(SerializedNames.REDIRECT)
106104
private String mRedirect;
107105

108106
/**
109107
* The client id of the application.
110108
*/
111-
@NonNull
112109
@SerializedName(SerializedNames.CLIENT_ID)
113110
private String mClientId;
114111

common/src/main/java/com/microsoft/identity/common/internal/broker/ipc/BrokerOperationBundle.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ public enum Operation {
7676
BROKER_INDIVIDUAL_LOGS_UPLOAD(API.BROKER_INDIVIDUAL_LOGS_UPLOAD, null),
7777
BROKER_API_RESTORE_MSA_ACCOUNTS_WITH_TRANSFER_TOKENS(API.BROKER_RESTORE_MSA_ACCOUNTS_WITH_TRANSFER_TOKENS, null),
7878
BROKER_WEBAPPS_API_GET_SUPPORTED_WEB_APPS_CONTRACTS(API.WEBAPPS_GET_SUPPORTED_WEB_APPS_CONTRACTS, null),
79-
BROKER_WEBAPPS_API_EXECUTE_WEB_APPS_REQUEST(API.WEBAPPS_EXECUTE_WEB_APPS_REQUEST, null);
79+
BROKER_WEBAPPS_API_EXECUTE_WEB_APPS_REQUEST(API.WEBAPPS_EXECUTE_WEB_APPS_REQUEST, null),
80+
PROVISION_RESOURCE_ACCOUNT(API.PROVISION_RESOURCE_ACCOUNT, null);
8081

8182
final API mContentApi;
8283
final String mAccountManagerOperation;

common/src/main/java/com/microsoft/identity/common/internal/controllers/BrokerMsalController.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import static com.microsoft.identity.common.internal.broker.ipc.BrokerOperationBundle.Operation.MSAL_REMOVE_ACCOUNT;
4040
import static com.microsoft.identity.common.internal.broker.ipc.BrokerOperationBundle.Operation.MSAL_SIGN_OUT_FROM_SHARED_DEVICE;
4141
import static com.microsoft.identity.common.internal.broker.ipc.BrokerOperationBundle.Operation.MSAL_SSO_TOKEN;
42+
import static com.microsoft.identity.common.internal.broker.ipc.BrokerOperationBundle.Operation.PROVISION_RESOURCE_ACCOUNT;
4243
import static com.microsoft.identity.common.internal.controllers.BrokerOperationExecutor.BrokerOperation;
4344
import static com.microsoft.identity.common.java.AuthenticationConstants.LocalBroadcasterAliases.RETURN_BROKER_INTERACTIVE_ACQUIRE_TOKEN_RESULT;
4445
import static com.microsoft.identity.common.java.AuthenticationConstants.LocalBroadcasterFields.REQUEST_CODE;
@@ -86,6 +87,7 @@
8687
import com.microsoft.identity.common.java.commands.parameters.GenerateShrCommandParameters;
8788
import com.microsoft.identity.common.java.commands.parameters.InteractiveTokenCommandParameters;
8889
import com.microsoft.identity.common.java.commands.parameters.RemoveAccountCommandParameters;
90+
import com.microsoft.identity.common.java.commands.parameters.ResourceAccountCommandParameters;
8991
import com.microsoft.identity.common.java.commands.parameters.RopcTokenCommandParameters;
9092
import com.microsoft.identity.common.java.commands.parameters.SilentTokenCommandParameters;
9193
import com.microsoft.identity.common.java.commands.parameters.TokenCommandParameters;
@@ -1181,7 +1183,62 @@ public void putValueInSuccessEvent(@NonNull final ApiEndEvent event,
11811183
// TODO Needed?
11821184
}
11831185
});
1186+
}
1187+
1188+
/**
1189+
* Sign in a resource account in broker based on given parameters. Should called by OneAuth/MSAL
1190+
* to provision resource account in broker.
1191+
* @param parameters a {@link ResourceAccountCommandParameters}
1192+
*/
1193+
public ICacheRecord provisionResourceAccount(@NonNull final ResourceAccountCommandParameters parameters) throws BaseException {
1194+
return getBrokerOperationExecutor().execute(parameters,
1195+
new BrokerOperation<ICacheRecord>() {
1196+
private String negotiatedBrokerProtocolVersion;
1197+
1198+
@Override
1199+
public void performPrerequisites(final @NonNull IIpcStrategy strategy) throws BaseException {
1200+
negotiatedBrokerProtocolVersion = hello(strategy, parameters.getRequiredBrokerProtocolVersion());
1201+
}
11841202

1203+
@Override
1204+
@NonNull
1205+
public BrokerOperationBundle getBundle() {
1206+
return new BrokerOperationBundle(
1207+
PROVISION_RESOURCE_ACCOUNT,
1208+
mActiveBrokerPackageName,
1209+
mRequestAdapter.getRequestBundleForProvisionResourceAccount(
1210+
parameters,
1211+
negotiatedBrokerProtocolVersion
1212+
));
1213+
}
1214+
1215+
@Override
1216+
@NonNull
1217+
public ICacheRecord extractResultBundle(final @Nullable Bundle resultBundle) throws BaseException {
1218+
if (resultBundle == null) {
1219+
throw mResultAdapter.getExceptionForEmptyResultBundle();
1220+
}
1221+
verifyBrokerVersionIsSupported(resultBundle, parameters.getRequiredBrokerProtocolVersion());
1222+
return mResultAdapter.resourceAccountRecordFromBundle(resultBundle);
1223+
}
1224+
1225+
@Override
1226+
public @NonNull
1227+
String getMethodName() {
1228+
return ":provisionResourceAccount";
1229+
}
1230+
1231+
@Nullable
1232+
@Override
1233+
public String getTelemetryApiId() {
1234+
return null;
1235+
}
1236+
1237+
@Override
1238+
public void putValueInSuccessEvent(@lombok.NonNull ApiEndEvent event, @lombok.NonNull ICacheRecord result) {
1239+
1240+
}
1241+
});
11851242
}
11861243

11871244
/**

common/src/main/java/com/microsoft/identity/common/internal/request/MsalBrokerRequestAdapter.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import com.microsoft.identity.common.java.commands.parameters.DeviceCodeFlowCommandParameters;
5555
import com.microsoft.identity.common.java.commands.parameters.GenerateShrCommandParameters;
5656
import com.microsoft.identity.common.java.commands.parameters.RemoveAccountCommandParameters;
57+
import com.microsoft.identity.common.java.commands.parameters.ResourceAccountCommandParameters;
5758
import com.microsoft.identity.common.java.opentelemetry.SerializableSpanContext;
5859
import com.microsoft.identity.common.java.opentelemetry.SpanExtension;
5960
import com.microsoft.identity.common.java.providers.microsoft.microsoftsts.MicrosoftStsAuthorizationResult;
@@ -264,6 +265,49 @@ public Bundle getRequestBundleForAcquireTokenInteractive(@NonNull final Interact
264265
);
265266
}
266267

268+
/**
269+
* Method to construct a request bundle for broker provisionResourceAccountRequest request.
270+
* @param parameters input parameters of type {@link ResourceAccountCommandParameters}
271+
* @param negotiatedBrokerProtocolVersion protocol version established by broker hello.
272+
* @return request Bundle
273+
*/
274+
public Bundle getRequestBundleForProvisionResourceAccount(
275+
@NonNull final ResourceAccountCommandParameters parameters,
276+
@Nullable final String negotiatedBrokerProtocolVersion
277+
) {
278+
final String methodTag = TAG + ":getRequestBundleForProvisionResourceAccount";
279+
280+
Logger.info(methodTag, "Constructing result bundle from ProvisionResourceAccount.");
281+
final String extraOptions = parameters.getExtraOptions() != null ?
282+
QueryParamsAdapter._toJson(parameters.getExtraOptions()) : null;
283+
284+
final BrokerRequest brokerRequest = BrokerRequest.builder()
285+
.authority(parameters.getAuthority().getAuthorityURL().toString())
286+
.extraOptions(extraOptions)
287+
.homeAccountId(parameters.getHomeAccountId())
288+
.userName(parameters.getLoginHint())
289+
.correlationId(parameters.getCorrelationId())
290+
.clientId(parameters.getClientId())
291+
.applicationName(parameters.getApplicationName())
292+
.applicationVersion(parameters.getApplicationVersion())
293+
.msalVersion(parameters.getSdkVersion())
294+
.sdkType(parameters.getSdkType())
295+
.environment(AzureActiveDirectory.getEnvironment().name())
296+
.powerOptCheckEnabled(parameters.isPowerOptCheckEnabled())
297+
.spanContext(SerializableSpanContext.builder()
298+
.traceId(SpanExtension.current().getSpanContext().getTraceId())
299+
.spanId(SpanExtension.current().getSpanContext().getSpanId())
300+
.traceFlags(SpanExtension.current().getSpanContext().getTraceFlags().asByte())
301+
.build()
302+
)
303+
.build();
304+
return getRequestBundleFromBrokerRequest(
305+
brokerRequest,
306+
negotiatedBrokerProtocolVersion,
307+
parameters.getRequiredBrokerProtocolVersion()
308+
);
309+
}
310+
267311
/**
268312
* Method to construct a request bundle for broker deviceCodeFlowAuthRequest request.
269313
*

common/src/main/java/com/microsoft/identity/common/internal/result/MsalBrokerResultAdapter.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,26 @@ public List<ICacheRecord> getAccountsFromResultBundle(@NonNull final Bundle bund
905905
return JsonExtensions.getICacheRecordListFromJsonString(accountJson);
906906
}
907907

908+
/**
909+
* Get resource account record from the result bundle. If successful, new account
910+
* record part of ICachedRecord is returned.
911+
* @param bundle The result bundle from the broker.
912+
* @throws BaseException
913+
*/
914+
public ICacheRecord resourceAccountRecordFromBundle(@NonNull final Bundle bundle) throws BaseException {
915+
final String methodTag = TAG + ":resourceAccountRecordFromBundle";
916+
final List<ICacheRecord> cacheRecords = getAccountsFromResultBundle(bundle);
917+
if (cacheRecords.isEmpty()) {
918+
Logger.error(methodTag, "No accounts found in the result bundle", null);
919+
throw new ClientException(INVALID_BROKER_BUNDLE, "No accounts found in the result bundle");
920+
}
921+
if (cacheRecords.size() > 1) {
922+
Logger.error(methodTag, "Multiple accounts found in the result bundle", null);
923+
throw new ClientException(INVALID_BROKER_BUNDLE, "Multiple accounts found in the result bundle");
924+
}
925+
return cacheRecords.get(0);
926+
}
927+
908928
public void verifyRemoveAccountResultFromBundle(@Nullable final Bundle bundle) throws BaseException {
909929
final String methodTag = TAG + ":verifyRemoveAccountResultFromBundle";
910930
if (bundle == null) {

common/src/test/java/com/microsoft/identity/common/internal/controllers/BrokerMsalControllerTest.java

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,27 @@
2222
// THE SOFTWARE.
2323
package com.microsoft.identity.common.internal.controllers;
2424

25-
import android.content.Context;
2625
import android.os.Build;
2726
import android.os.Bundle;
2827

2928
import androidx.annotation.NonNull;
30-
import androidx.annotation.Nullable;
3129
import androidx.test.platform.app.InstrumentationRegistry;
3230

3331
import com.google.gson.Gson;
3432
import com.microsoft.identity.common.adal.internal.AuthenticationConstants;
3533
import com.microsoft.identity.common.components.MockPlatformComponentsFactory;
36-
import com.microsoft.identity.common.exception.BrokerCommunicationException;
3734
import com.microsoft.identity.common.internal.broker.ipc.BrokerOperationBundle;
3835
import com.microsoft.identity.common.internal.broker.ipc.IIpcStrategy;
36+
import com.microsoft.identity.common.internal.result.MsalBrokerResultAdapter;
37+
import com.microsoft.identity.common.java.authorities.Authority;
38+
import com.microsoft.identity.common.java.cache.CacheRecord;
39+
import com.microsoft.identity.common.java.cache.ICacheRecord;
3940
import com.microsoft.identity.common.java.commands.AcquirePrtSsoTokenResult;
4041
import com.microsoft.identity.common.java.commands.parameters.AcquirePrtSsoTokenCommandParameters;
42+
import com.microsoft.identity.common.java.commands.parameters.ResourceAccountCommandParameters;
43+
import com.microsoft.identity.common.java.dto.AccountRecord;
4144
import com.microsoft.identity.common.java.interfaces.IPlatformComponents;
45+
import com.microsoft.identity.common.java.request.SdkType;
4246

4347
import org.junit.Assert;
4448
import org.junit.Test;
@@ -47,7 +51,8 @@
4751
import org.robolectric.annotation.Config;
4852

4953
import java.util.Collections;
50-
import java.util.List;
54+
55+
import lombok.SneakyThrows;
5156

5257
@RunWith(RobolectricTestRunner.class)
5358
@Config(sdk = {Build.VERSION_CODES.N}, shadows = {})
@@ -125,4 +130,72 @@ public Type getType() {
125130
Assert.assertEquals("x-ms-RefreshTokenCredential", ssoTokenResult.getCookieName());
126131
}
127132

133+
/**
134+
* This test simulates a result calling the ProvisionResourceAccount Api.
135+
*/
136+
@SneakyThrows
137+
@Test
138+
public void testProvisionResourceAccount() {
139+
final String mockHomeAccountId = "mockHomeAccountId";
140+
final String mockCorrelationId = "mockCorrelationId";
141+
final String mockAuthorityStr = "https://login.microsoft.com/mockAuthority";
142+
final Authority mockAuthority = Authority.getAuthorityFromAuthorityUrl(mockAuthorityStr);
143+
final String mockNegotiatedBrokerVersion = "18.0";
144+
final String mockAccountName = "mockAccountName";
145+
final AccountRecord mockAccountRecord = new AccountRecord();
146+
mockAccountRecord.setHomeAccountId(mockHomeAccountId);
147+
mockAccountRecord.setUsername(mockAccountName);
148+
final CacheRecord mockCacheRecord = CacheRecord.builder()
149+
.account(mockAccountRecord)
150+
.build();
151+
final MsalBrokerResultAdapter resultAdapter = new MsalBrokerResultAdapter();
152+
final IIpcStrategy strategy = new IIpcStrategy() {
153+
@Override
154+
public Bundle communicateToBroker(@NonNull BrokerOperationBundle bundle) {
155+
Bundle retBundle = new Bundle();
156+
if (bundle.getOperation().equals(BrokerOperationBundle.Operation.MSAL_HELLO)) {
157+
retBundle.putString(AuthenticationConstants.Broker.NEGOTIATED_BP_VERSION_KEY, mockNegotiatedBrokerVersion);
158+
} else if (bundle.getOperation().equals(BrokerOperationBundle.Operation.PROVISION_RESOURCE_ACCOUNT)) {
159+
retBundle = resultAdapter.bundleFromAccounts(Collections.singletonList(mockCacheRecord), mockNegotiatedBrokerVersion);
160+
}
161+
return retBundle;
162+
}
163+
164+
@Override
165+
public boolean isSupportedByTargetedBroker(@NonNull final String targetedBrokerPackageName) {
166+
return true;
167+
}
168+
169+
@Override
170+
@NonNull
171+
public Type getType() {
172+
return Type.CONTENT_PROVIDER;
173+
}
174+
};
175+
176+
final IPlatformComponents components = MockPlatformComponentsFactory.getNonFunctionalBuilder().build();
177+
final ResourceAccountCommandParameters parameters = ResourceAccountCommandParameters.builder()
178+
.platformComponents(components)
179+
.homeAccountId(mockHomeAccountId)
180+
.authority(mockAuthority)
181+
.correlationId(mockCorrelationId)
182+
.applicationName("mockApplicationName")
183+
.applicationVersion("mockApplicationVersion")
184+
.sdkVersion("mockSdkVersion")
185+
.sdkType(SdkType.MSAL)
186+
.requiredBrokerProtocolVersion(mockNegotiatedBrokerVersion)
187+
.build();
188+
189+
final BrokerMsalController controller = new BrokerMsalController(
190+
InstrumentationRegistry.getInstrumentation().getContext(),
191+
components,
192+
"aBrokerPackage",
193+
Collections.singletonList(strategy));
194+
195+
final ICacheRecord cacheRecord = controller.provisionResourceAccount(parameters);
196+
197+
// verify the cache record
198+
Assert.assertEquals(mockHomeAccountId, cacheRecord.getAccount().getHomeAccountId());
199+
Assert.assertEquals(mockAccountName, cacheRecord.getAccount().getUsername());
200+
}
128201
}

0 commit comments

Comments
 (0)