Device Trust od Android Enterprise – przewodnik integracji

.

Ten dokument powinien być Twoim głównym przewodnikiem po pakiecie AMAPI SDK na potrzeby otrzymywania sygnałów zaufania urządzenia.

Pakiet SDK AMAPI umożliwia aplikacji (którą czasami nazywamy aplikacją „towarzyszącą”) dostęp do sygnałów o zaufaniu do urządzenia z aplikacji ADP (Android Device Policy). Aplikacja może następnie używać tych sygnałów do obliczania stanu zaufania urządzenia i wdrażania wybranej logiki biznesowej.

Wymagania wstępne

  • Dostęp do sygnałów zaufania urządzenia jest ograniczony, aby zapobiec nieautoryzowanemu użyciu. Informacje o tym, jak złożyć wniosek, znajdziesz na stronie dostępu do sygnałów zaufania urządzenia.
  • Android Enterprise zaleca zintegrowanie pakietu interfejsów Play Integrity z aplikacją klienta i odwoływanie się do wyników przed odczytaniem i używaniem sygnałów zaufania urządzenia. Urządzenia, które nie przechodzą kontroli interfejsu Play Integrity API, nie powinny być uznawane za godne zaufania, podobnie jak sygnały pochodzące z urządzenia używanego do określania zaufania. Aby dowiedzieć się więcej, zapoznaj się z dokumentacją dotyczącą integralności w Google Play.

Integracja pakietu AMAPI SDK z aplikacją

Aby uzyskać dostęp do sygnałów zaufania urządzenia, aplikacja musi zostać zintegrowana z pakietem AMAPI SDK. Więcej informacji o tej bibliotece i sposobie jej dodania do aplikacji znajdziesz w przewodniku po integracji pakietu AMAPI SDK.

Dodawanie wymaganych uprawnień

Niektóre sygnały zwracane przez interfejs API zaufanie urządzenia w Androidzie Enterprise wymagają, aby aplikacja deklarowała te same uprawnienia, które byłyby wymagane do uzyskania dostępu do tych informacji. W szczególności:

Sygnał Wymagane uprawnienie
Stan sieci ACCESS_NETWORK_STATE
Złożoność blokady ekranu REQUEST_PASSWORD_COMPLEXITY

Jeśli te uprawnienia nie są uwzględnione w AndroidManifest.xml aplikacji, zaufanie do urządzenia z Androida Enterprise zwraca wartość PERMISSION_ISSUE w metadanych powiązanego sygnału:

internalDeviceSettings=DeviceSettings{
  screenLockComplexity=COMPLEXITY_UNSPECIFIED,
  internalScreenLockComplexityMetadata=Metadata{
    dataIssues=[
      DataIssue{
        issueType=PERMISSION_ISSUE,
        issueLevel=WARNING,
        issueDetails=IssueDetailsCase{none}
      }
    ]
  },

Więcej informacji znajdziesz na liście dostępnych sygnałów zaufania urządzenia.

Jak uzyskać dostęp do sygnałów zaufania urządzenia

Aplikacje, które chcą uzyskać dostęp do sygnałów zaufania urządzenia, muszą zweryfikować, czy środowisko klienta jest aktualne, i w razie potrzeby je zaktualizować.

Aby uzyskać dostęp do sygnałów zaufania do urządzenia:

Weryfikacja środowiska klienta

Z przykładu kodu poniżej dowiesz się, jak za pomocą funkcji getEnvironment odczytać bieżący stan aplikacji ADP. Następnie aplikacja może utworzyć obiekt deviceClient, aby uzyskać dostęp do sygnałów zaufania urządzenia, jeśli środowisko jest gotowe i aktualne (patrz Dostęp do sygnałów zaufania urządzenia).

Kotlin

import com.google.android.managementapi.common.model.Role
import com.google.android.managementapi.device.DeviceClient
import com.google.android.managementapi.device.DeviceClientFactory
import com.google.android.managementapi.device.model.GetDeviceRequest
import com.google.android.managementapi.environment.EnvironmentClient
import com.google.android.managementapi.environment.EnvironmentClientFactory
import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.INSTALLED
import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.NOT_INSTALLED
import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.READY
import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.Version.UP_TO_DATE
import com.google.android.managementapi.environment.model.GetEnvironmentRequest
import com.google.android.managementapi.environment.model.PrepareEnvironmentRequest

try {
    val context = applicationContext

    val roles = listOf(Role.builder().setRoleType(Role.RoleType.IDENTITY_PROVIDER).build())
    val request = GetEnvironmentRequest.builder().setRoles(roles).build()
    val environmentClient = EnvironmentClientFactory.create(context)
    val environmentResponse = environmentClient.getEnvironment(request)

    if (environmentResponse.hasAndroidDevicePolicyEnvironment()) {
        val adpEnvironment = environmentResponse.androidDevicePolicyEnvironment

        if (adpEnvironment.state == READY && adpEnvironment.version == UP_TO_DATE) {
            // AMAPI Environment State OK, Version OK.  Requesting Device signals..
            checkDevice(deviceClient = DeviceClientFactory.create(context))
        } else if (adpEnvironment.state == INSTALLED) {
            // prepareEnvironment should be called, calling
            // prepareEnvironment won't show the UI
            prepareEnvironment(context, environmentClient)
        } else if (adpEnvironment.state == NOT_INSTALLED) {
            // prepareEnvironment should be called, calling
            // prepareEnvironment will show the UI
            prepareEnvironment(context, environmentClient)
        }
    }
} catch (e: Exception) {
    Log.e(TAG, "Exception", e)
}

Java

import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.INSTALLED;
import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.NOT_INSTALLED;
import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.READY;
import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.Version.UP_TO_DATE;

import com.google.android.managementapi.common.model.Role;
import com.google.android.managementapi.device.DeviceClient;
import com.google.android.managementapi.device.DeviceClientFactory;
import com.google.android.managementapi.device.model.Device;
import com.google.android.managementapi.device.model.GetDeviceRequest;
import com.google.android.managementapi.environment.EnvironmentClient;
import com.google.android.managementapi.environment.EnvironmentClientFactory;
import com.google.android.managementapi.environment.model.Environment;
import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment;
import com.google.android.managementapi.environment.model.GetEnvironmentRequest;
import com.google.android.managementapi.environment.model.PrepareEnvironmentRequest;
import com.google.android.managementapi.environment.model.PrepareEnvironmentResponse;

try {
    Context context = getApplicationContext();

    ImmutableList roles = new ImmutableList.Builder()
            .add(Role.builder()
                    .setRoleType(Role.RoleType.IDENTITY_PROVIDER)
                    .build())
            .build();

    EnvironmentClient environmentClient = EnvironmentClientFactory.create(context);
    GetEnvironmentRequest request = GetEnvironmentRequest.builder()
            .setRoles(roles)
            .build();

    ListenableFuture getEnvironmentFuture = environmentClient.getEnvironmentAsync(request);
    Futures.addCallback(getEnvironmentFuture, new FutureCallback<>() {
        @Override
        public void onSuccess(Environment environment) {
            AndroidDevicePolicyEnvironment adpEnvironment = environment.getAndroidDevicePolicyEnvironment();

            AndroidDevicePolicyEnvironment.State state = adpEnvironment.getState();
            AndroidDevicePolicyEnvironment.Version version = adpEnvironment.getVersion();
            if (state == READY && version == UP_TO_DATE) {
                // AMAPI Environment State OK, Version OK.  Requesting Device signals..
                DeviceClient deviceClient = DeviceClientFactory.create(context);
                checkDevice(deviceClient);
            } else if (state == INSTALLED) {
                // prepareEnvironment should be called, calling
                // prepareEnvironment won't show the UI
                prepareEnvironment(context, environmentClient);
            } else if (state == NOT_INSTALLED) {
                // prepareEnvironment should be called, calling
                // prepareEnvironment will show the UI
                prepareEnvironment(context, environmentClient);
            }
        }

        @Override
        public void onFailure(Throwable t) {
            Log.d(TAG, t.toString());
        }
    }, MoreExecutors.directExecutor());
} catch (Exception e) {
    Log.d(TAG, e.toString());
}

Jeśli aplikacja ADP jest zainstalowana, ale nie jest aktualna, Twoja aplikacja powinna wywołać funkcję prepareEnvironment, aby dyskretnie zaktualizować aplikację ADP bez udziału użytkownika.

Jeśli aplikacja ADP nie jest zainstalowana, może wywołać funkcję prepareEnvironment, aby poprosić użytkownika o zainstalowanie aplikacji ADP. Zapoznaj się z sekcją Przygotowanie środowiska klienta.

Przygotowanie środowiska klienta

  • Jeśli aplikacja ADP jest już zainstalowana, interfejs API zaktualizuje ją bez udziału użytkownika.

  • Jeśli aplikacja ADP nie jest zainstalowana, interfejs API poprosi użytkownika o zaakceptowanie instalacji aplikacji ADP.

Zainstaluj Android Device Policy

Aby monitorować wybór użytkownika, możesz zarejestrować wywołanie zwrotne. Więcej informacji znajdziesz w artykule Śledzenie interakcji użytkowników podczas instalacji aplikacji ADP.

Zalecamy, aby wywołanie prepareEnvironment było wykonywane w procesie czołowym podczas procesu wprowadzania użytkownika, aby nie zaskakiwać go oknem modalnym Zainstaluj Android Device Policy. Jeśli wywołanie z procesu na pierwszym planie jest niemożliwe, ponieważ jest to proces internetowy, a komponent na Androida nie ma interfejsu użytkownika, wywołanie z tła jest dozwolone, ale tylko podczas procesu wdrażania.

Po prawidłowym skonfigurowaniu środowiska można uzyskać dostęp do sygnałów zaufania urządzenia. Zapoznaj się z artykułem Dostęp do sygnałów o zaufaniu do urządzenia.

Kotlin

try {
    val myNotificationReceiverService = ComponentName(
        context, MyNotificationReceiverService::class.java
    )

    val roles = listOf(Role.builder().setRoleType(Role.RoleType.IDENTITY_PROVIDER).build())
    val request = PrepareEnvironmentRequest.builder().setRoles(roles).build()

    val response =
        environmentClient.prepareEnvironment(request, myNotificationReceiverService)

    val environment = response.environment
    val adpEnvironment = environment.androidDevicePolicyEnvironment

    val state = adpEnvironment.state
    val version = adpEnvironment.version
    if (state == READY && version == UP_TO_DATE) {
        // Environment is prepared, access device posture signals using
        // DeviceClient.
        checkDevice(deviceClient = DeviceClientFactory.create(context))
    } else {
        // The prepareEnvironment call failed to prepare
        Log.w(
            TAG, "AMAPI environment was not ready: " + state + " - " + version
        )
    }

} catch (e: java.lang.Exception) {
    Log.d(TAG, e.toString())
}

Java

try {
    ComponentName myNotificationReceiverService = new ComponentName(
            context,
            MyNotificationReceiverService.class
    );

    ImmutableList roles = new ImmutableList.Builder()
            .add(Role.builder()
                    .setRoleType(Role.RoleType.IDENTITY_PROVIDER)
                    .build())
            .build();


    PrepareEnvironmentRequest request = PrepareEnvironmentRequest.builder()
            .setRoles(roles)
            .build();

    ListenableFuture environmentFuture =
            environmentClient.prepareEnvironmentAsync(
                    request,
                    myNotificationReceiverService
            );

    Futures.addCallback(environmentFuture, new FutureCallback<>() {
        @Override
        public void onSuccess(PrepareEnvironmentResponse response) {
            Environment environment = response.getEnvironment();
            AndroidDevicePolicyEnvironment adpEnvironment = environment.getAndroidDevicePolicyEnvironment();

            AndroidDevicePolicyEnvironment.State state = adpEnvironment.getState();
            AndroidDevicePolicyEnvironment.Version version = adpEnvironment.getVersion();
            if (state == READY && version == UP_TO_DATE) {
                // AMAPI Environment State OK, Version OK.  Requesting Device signals..
                DeviceClient deviceClient = DeviceClientFactory.create(context);
                checkDevice(deviceClient);
            } else {
                // The prepareEnvironment call failed to prepare
                Log.w(
                        TAG, "AMAPI environment was not ready: "
                        + adpEnvironment.getState() + " - " + adpEnvironment.getVersion()
                );
            }
        }

        @Override
        public void onFailure(@NonNull Throwable t) {
            // Handle the error
            Log.d(TAG, "AMAPI response did not contain an ADP environment");
        }
    }, MoreExecutors.directExecutor());
} catch (Exception e) {
    Log.d(TAG, e.toString());
}

Dostęp do sygnałów zaufania do urządzenia

Aby uzyskać dostęp do interesujących Cię sygnałów zaufania urządzenia, możesz użyć instancji deviceClient, którą widzisz w poprzednim kroku, aby zażądać obiektu Device.

Kotlin

try {
    kotlin.runCatching {
        deviceClient.getDeviceAwait(GetDeviceRequest.getDefaultInstance())
    }.onFailure { t ->
        Log.d(TAG, t.toString())
    }.onSuccess { device ->
        // Access device posture signals available in device
        val deviceString = device.toString()
        Log.d(TAG, deviceString)
    }
} catch (e: java.lang.Exception) {
    Log.d(TAG, e.toString())
}

Java

try {
    ListenableFuture deviceFuture =
            deviceClient.getDevice(GetDeviceRequest.getDefaultInstance());

    Futures.addCallback(deviceFuture, new FutureCallback() {
        @Override
        public void onSuccess(Device device) {
            // Access device posture signals available in device
            String deviceString = device.toString();
            Log.d(TAG, deviceString);
        }

        @Override
        public void onFailure(Throwable t) {
            Log.d(TAG, Log.d(TAG, t.toString());
        }
    }, MoreExecutors.directExecutor());
} catch (Exception e) {
    Log.d(TAG, e.toString());
}

Śledzenie interakcji użytkownika podczas instalowania aplikacji ADP

Jeśli podczas prepareEnvironment aplikacja musi zainstalować aplikację ADP, może śledzić interakcje użytkownika, wdrażając NotificationReceiverService, aby otrzymywać powiadomienia, które zastąpią getPrepareEnvironmentListener:

Kotlin

import android.util.Log
import com.google.android.managementapi.environment.EnvironmentListener
import com.google.android.managementapi.environment.model.EnvironmentEvent.EventCase.Kind.ANDROID_DEVICE_POLICY_INSTALL_CONSENT_ACCEPTED
import com.google.android.managementapi.environment.model.EnvironmentEvent
import com.google.android.managementapi.notification.NotificationReceiverService

class MyNotificationReceiverService : NotificationReceiverService() {
    override fun getPrepareEnvironmentListener(): EnvironmentListener {
        return MyEnvironmentListener()
    }
}

class MyEnvironmentListener : EnvironmentListener {
    override fun onEnvironmentEvent(
        event: EnvironmentEvent
    ) {
        if (event.event.kind == ANDROID_DEVICE_POLICY_INSTALL_CONSENT_ACCEPTED) {
            Log.d(TAG, "User provided install consent")
        } else {
            Log.d(TAG, "User rejected install consent")
        }
    }

    companion object {
        private val TAG: String = MyEnvironmentListener::class.java.simpleName
    }
}

Java

import static com.google.android.managementapi.environment.model.EnvironmentEvent.EventCase.Kind.ANDROID_DEVICE_POLICY_INSTALL_CONSENT_ACCEPTED;

import android.util.Log;
import androidx.annotation.NonNull;
import com.google.android.managementapi.environment.EnvironmentListener;
import com.google.android.managementapi.environment.model.EnvironmentEvent;
import com.google.android.managementapi.notification.NotificationReceiverService;

class MyNotificationReceiverService extends NotificationReceiverService {
    @NonNull
    @Override
    protected EnvironmentListener getPrepareEnvironmentListener() {
        return new MyEnvironmentListener();
    }
}
class MyEnvironmentListener implements EnvironmentListener {
    final private String TAG = MyEnvironmentListener.class.getSimpleName();

    @Override
    public void onEnvironmentEvent(EnvironmentEvent event) {
        if (event.getEvent().getKind() == ANDROID_DEVICE_POLICY_INSTALL_CONSENT_ACCEPTED)
        {
            Log.d(TAG, "User provided install consent");
        } else {
            Log.d(TAG, "User rejected install consent");
        }
    }
}

Znane problemy

Obecnie nie ma żadnych znanych problemów.