Device Trust od Android Enterprise – przewodnik integracji

.

Ten dokument powinien być głównym przewodnikiem po korzystaniu z pakietu AMAPI SDK w celu otrzymywania sygnałów zaufania urządzenia.

Pakiet SDK AMAPI umożliwia aplikacji (którą czasami nazywamy aplikacją towarzyszącą) dostęp do sygnałów zaufania 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ęp do sygnałów zaufania urządzenia.
  • Android Enterprise zaleca zintegrowanie pakietu interfejsów Play Integrity API z aplikacją kliencką i odwoływanie się do wyniku przed odczytaniem sygnałów zaufania urządzenia i poleganiem na nich. Urządzenia, które nie przejdą weryfikacji interfejsu Play Integrity API, nie powinny być uznawane za zaufane. Nie należy też ufać żadnym sygnałom pochodzącym z urządzenia używanego do określania poziomu zaufania. Więcej informacji znajdziesz w dokumentacji usługi Play Integrity.

Integracja z pakietem AMAPI SDK w aplikacji

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

Dodawanie wymaganych uprawnień

Niektóre sygnały zwracane przez interfejs Device Trust z Androida Enterprise wymagają, aby aplikacja deklarowała to samo uprawnienie, które byłoby wymagane do uzyskania dostępu do tych informacji, w szczególności:

Sygnał Wymagane uprawnienie
Stan sieci ACCESS_NETWORK_STATE
Stopień złożoności blokady ekranu REQUEST_PASSWORD_COMPLEXITY

Jeśli te uprawnienia nie są uwzględnione w AndroidManifest.xml aplikacji, interfejs Device Trust z Androida Enterprise API zwróci 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.

Instrukcje uzyskiwania dostępu do sygnałów zaufania urządzenia

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

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

Instrukcje uzyskiwania dostępu do sygnałów zaufania urządzenia

Weryfikacja środowiska klienta

Poniższy przykład kodu pokazuje, jak używać funkcji getEnvironment do odczytywania bieżącego stanu aplikacji ADP. Aplikacja może następnie utworzyć obiekt deviceClient, aby uzyskać dostęp do sygnałów zaufania urządzenia, jeśli środowisko jest gotowe i aktualne (patrz Uzyskiwanie dostępu 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 interakcji ze strony użytkownika.

Jeśli aplikacja ADP nie jest zainstalowana, Twoja aplikacja może wywołać prepareEnvironment, aby poprosić użytkownika o jej zainstalowanie. Więcej informacji znajdziesz w sekcji Przygotowywanie środowiska klienta.

Przygotowywanie środowiska klienta

  • Jeśli aplikacja ADP jest już zainstalowana, interfejs API zaktualizuje ją w trybie cichym bez interwencji użytkownika.

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

Zainstaluj Android Device Policy

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

Zalecamy, aby wywołanie prepareEnvironment było wykonywane z procesu działającego na pierwszym planie podczas procesu wprowadzającego, aby uniknąć zaskoczenia użytkownika modalnym oknem Zainstaluj aplikację Android Device Policy. Jeśli wywołanie z procesu na pierwszym planie nie jest możliwe, ponieważ jest to przepływ internetowy, a komponent Androida nie ma interfejsu, wywołanie z procesu w tle jest dozwolone pod warunkiem, że następuje w trakcie przepływu UX związanego z wprowadzeniem.

Po prawidłowym skonfigurowaniu środowiska można uzyskać dostęp do sygnałów zaufania urządzenia. Zobacz Dostęp do sygnałów zaufania 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 sygnałów zaufania urządzenia, które Cię interesują, możesz użyć instancji deviceClient widocznej w poprzednim kroku, aby poprosić o obiekt 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 instalacji aplikacji ADP

Jeśli urządzenie musi zainstalować aplikację ADP podczas prepareEnvironment, Twoja aplikacja może śledzić interakcje użytkownika, implementując NotificationReceiverService, aby otrzymywać powiadomienia zastępujące 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.