Skip to content

Commit

Permalink
Merge branch 'dev' into shahzaibj/onebox-support
Browse files Browse the repository at this point in the history
  • Loading branch information
shahzaibj committed Dec 27, 2024
2 parents 0838bc6 + e29fcf1 commit 3edf930
Show file tree
Hide file tree
Showing 5 changed files with 311 additions and 2 deletions.
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
vNext
----------
- [MINOR] Add SDMBroadcastReceiver for applications to register callbacks for SDM broadcasts (#2547)
- [MINOR] Add switch_browser toMicrosoftStsAuthorizationRequest (#2550)
- [MAJOR] Add suberror for network errors (#2537)
- [PATCH] Translate MFA token error to UIRequiredException instead of ServiceException (#2538)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package com.microsoft.identity.common.internal.broker;

import android.content.Intent;

import androidx.test.core.app.ApplicationProvider;

import com.microsoft.identity.common.java.constants.SharedDeviceModeConstants;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class SDMBroadcastReceiverTests {

String actualCallbackReceived;

@Before
public void setup() {
SDMBroadcastReceiver.initialize(ApplicationProvider.getApplicationContext(), new SDMBroadcastReceiver.SharedDeviceModeCallback() {
@Override
public void onSharedDeviceModeRegistrationStarted() {
actualCallbackReceived = SharedDeviceModeConstants.BROADCAST_TYPE_SDM_REGISTRATION_START;
}

@Override
public void onSharedDeviceModeRegistered() {
actualCallbackReceived = SharedDeviceModeConstants.BROADCAST_TYPE_SDM_REGISTERED;
}

@Override
public void onGlobalSignOut() {
actualCallbackReceived = SharedDeviceModeConstants.BROADCAST_TYPE_GLOBAL_SIGN_OUT;
}
});
}
@Test
public void testSDMBroadcast() throws InterruptedException {
sendBroadcast(SharedDeviceModeConstants.BROADCAST_TYPE_SDM_REGISTRATION_START);
Thread.sleep(100);
Assert.assertEquals(SharedDeviceModeConstants.BROADCAST_TYPE_SDM_REGISTRATION_START, actualCallbackReceived);

sendBroadcast(SharedDeviceModeConstants.BROADCAST_TYPE_GLOBAL_SIGN_OUT);
Thread.sleep(100);
Assert.assertEquals(SharedDeviceModeConstants.BROADCAST_TYPE_GLOBAL_SIGN_OUT, actualCallbackReceived);
}

private void sendBroadcast(String broadcastType) {
final Intent intent = new Intent();
intent.setAction(SharedDeviceModeConstants.CURRENT_ACCOUNT_CHANGED_BROADCAST_IDENTIFIER);
intent.putExtra(SharedDeviceModeConstants.BROADCAST_TYPE_KEY, broadcastType);
ApplicationProvider.getApplicationContext().sendBroadcast(intent);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package com.microsoft.identity.common.internal.broker;

import static com.microsoft.identity.common.java.cache.SharedPreferencesAccountCredentialCache.DEFAULT_ACCOUNT_CREDENTIAL_SHARED_PREFERENCES;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;

import androidx.annotation.NonNull;

import com.microsoft.identity.common.components.AndroidPlatformComponentsFactory;
import com.microsoft.identity.common.internal.activebrokerdiscovery.BrokerDiscoveryClientFactory;
import com.microsoft.identity.common.internal.controllers.BrokerMsalController;
import com.microsoft.identity.common.java.cache.CacheKeyValueDelegate;
import com.microsoft.identity.common.java.cache.IAccountCredentialCache;
import com.microsoft.identity.common.java.cache.SharedPreferencesAccountCredentialCache;
import com.microsoft.identity.common.java.commands.parameters.CommandParameters;
import com.microsoft.identity.common.java.constants.SharedDeviceModeConstants;
import com.microsoft.identity.common.java.exception.BaseException;
import com.microsoft.identity.common.java.interfaces.IPlatformComponents;
import com.microsoft.identity.common.logging.Logger;

import java.util.UUID;

/**
* Broadcast receiver listening for Shared device mode broadcasts from broker.
*/
public class SDMBroadcastReceiver {
private static final String TAG = SDMBroadcastReceiver.class.getSimpleName();
private static BroadcastReceiver sSDMBroadcastReceiver;

/**
* Initializes the SDM broadcast receiver to start listening for SDM broadcasts from broker
* @param context application context.
* @param sharedDeviceModeCallback a callback to be called when SDM broadcast is received.
*/
synchronized public static void initialize( @NonNull final Context context,
@NonNull final SharedDeviceModeCallback sharedDeviceModeCallback) {
if (sSDMBroadcastReceiver == null) {
sSDMBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
handleSharedDeviceModeBroadCast(context, intent, sharedDeviceModeCallback);
}
};

final IntentFilter filter = new IntentFilter(SharedDeviceModeConstants.CURRENT_ACCOUNT_CHANGED_BROADCAST_IDENTIFIER);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.registerReceiver(sSDMBroadcastReceiver, filter, Context.RECEIVER_EXPORTED);
} else {
context.registerReceiver(sSDMBroadcastReceiver, filter);
}
}
}

/**
* Handles the SDM broadcast and calls the callback method based on the broadcast type
* @param context application context.
* @param intent The receive intent for SDM broadcast.
* @param sharedDeviceModeCallback Callback to be called.
*/
private static void handleSharedDeviceModeBroadCast(@NonNull final Context context,
@NonNull final Intent intent,
@NonNull SharedDeviceModeCallback sharedDeviceModeCallback) {
final String methodTag = TAG + ":handleSharedDeviceModeBroadCast";
final String broadcastType = intent.getStringExtra(SharedDeviceModeConstants.BROADCAST_TYPE_KEY);
Logger.info(methodTag, "Received SDM broadcast with type: " + broadcastType);
try {
final IPlatformComponents platformComponents = AndroidPlatformComponentsFactory.createFromContext(context);
if (broadcastType == null) {
Logger.warn(methodTag, "ignoring null broadcast type ");
} else {
switch (broadcastType) {
case SharedDeviceModeConstants.BROADCAST_TYPE_SDM_REGISTRATION_START:
sharedDeviceModeCallback.onSharedDeviceModeRegistrationStarted();
break;
case SharedDeviceModeConstants.BROADCAST_TYPE_SDM_REGISTERED:
if (isDeviceInSharedMode(context, platformComponents)) {
Logger.info(methodTag, "Device is registered in SDM, clearing default account cache.");
final IAccountCredentialCache accountCredentialCache = new SharedPreferencesAccountCredentialCache(
new CacheKeyValueDelegate(),
platformComponents.getStorageSupplier().getEncryptedNameValueStore(
DEFAULT_ACCOUNT_CREDENTIAL_SHARED_PREFERENCES, String.class)
);
accountCredentialCache.clearAll();
sharedDeviceModeCallback.onSharedDeviceModeRegistered();
} else {
Logger.warn(methodTag, "Device not in shared device mode, ignore broadcast.");
}
break;
case SharedDeviceModeConstants.BROADCAST_TYPE_GLOBAL_SIGN_OUT:
sharedDeviceModeCallback.onGlobalSignOut();
break;
default:
Logger.warn(methodTag, "ignoring unknown broadcast type " + broadcastType);
break;
}
}
} catch (final BaseException e) {
Logger.error(methodTag, "Failed to handle SDM broadcast", e);
}
}

private static boolean isDeviceInSharedMode(@NonNull final Context context,
@NonNull IPlatformComponents platformComponents) throws BaseException {
final BrokerData activeBroker = BrokerDiscoveryClientFactory.getInstanceForBrokerSdk(context, platformComponents)
.getActiveBroker(false);
if (activeBroker == null) {
return false;
}
final BrokerMsalController brokerMsalController = new BrokerMsalController(context, platformComponents, activeBroker.getPackageName());
final CommandParameters commandParameters;
commandParameters = CommandParameters.builder()
.platformComponents(platformComponents)
.correlationId(UUID.randomUUID().toString())
.build();
return brokerMsalController.getDeviceMode(commandParameters);
}

/**
* Callback for SDM broadcasts
*/
public interface SharedDeviceModeCallback {
/**
* Called when shared device mode registration is initiated.
*/
void onSharedDeviceModeRegistrationStarted();

/**
* Called when device is registered in shared device mode.
*/
void onSharedDeviceModeRegistered();

/**
* Called when global sign out occurs.
*/
void onGlobalSignOut();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@

import android.content.Context;
import android.content.Intent;
import android.os.Parcelable;

import androidx.annotation.Nullable;

import com.microsoft.identity.common.java.util.IBroadcaster;
import com.microsoft.identity.common.java.util.ported.PropertyBag;
import com.microsoft.identity.common.logging.Logger;

import lombok.AllArgsConstructor;
import lombok.NonNull;
Expand All @@ -39,17 +39,20 @@
*/
@AllArgsConstructor
public class AndroidBroadcaster implements IBroadcaster {
private static final String TAG = AndroidBroadcaster.class.getSimpleName();

@NonNull
private final Context mContext;

@Override
public void sendBroadcast(@NonNull final String broadcastId, @Nullable final PropertyBag propertyBag) {
final String methodTag = TAG + ":sendBroadcast";
Logger.info(methodTag, "Sending broadcast with broadcastId: " + broadcastId);
final Intent intent = new Intent();
intent.setAction(broadcastId);
if(propertyBag != null) {
for (final String key : propertyBag.keySet()) {
intent.putExtra(key, propertyBag.<Parcelable[]>get(key));
intent.putExtra(key, propertyBag.<String>get(key));
}
}
mContext.sendBroadcast(intent);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package com.microsoft.identity.common.java.constants

/**
* Constants related to Shared Device Mode
*/
class SharedDeviceModeConstants {
companion object {
/**
* BroadcastId of the Account Change operation.
*/
const val CURRENT_ACCOUNT_CHANGED_BROADCAST_IDENTIFIER = "com.microsoft.identity.client.sharedmode.CURRENT_ACCOUNT_CHANGED"

/**
* Broadcast type key sent as extra in the broadcast intent
*/
const val BROADCAST_TYPE_KEY = "BROADCAST_TYPE"

/**
* Broadcast type for SDM registration start
*/
const val BROADCAST_TYPE_SDM_REGISTRATION_START = "SDM_REGISTRATION_START"

/**
* Broadcast type for SDM registration complete
*/
const val BROADCAST_TYPE_SDM_REGISTERED = "SDM_REGISTERED"

/**
* Broadcast type for SDM GLOBAL_SIGN_OUT
*/
const val BROADCAST_TYPE_GLOBAL_SIGN_OUT = "GLOBAL_SIGN_OUT"

/**
* Prefix for the account name used for the Device Account
* when performing userless shared device registration using preauthorized challenge
* The full account name is this prefix followed by the tenant-id
* where the device is getting registered.
*/
const val DEVICE_WORK_ACCOUNT_FOR_TENANT_PREFIX = "Device Work account for Tenant:"
}
}

0 comments on commit 3edf930

Please sign in to comment.