Lukas Schönbächler · juillet 2026 · 9 min de lecture
Pourquoi c’est important
- NTLM a une date butoir : NTLMv1 sera bloqué en octobre 2026 (KB5066470) et le NTLM réseau disparaîtra avec la prochaine version Windows Server LTSC. Les applications Android qui s’authentifient encore avec NTLM ont besoin d’un remplaçant, et ce remplaçant, c’est Kerberos.
- Le Hypergate SDK (
com.hypergate:sdksur Maven Central) ajoute des jetons de négociation SPNEGO à n’importe quelle application Android, pour que votre application réponde en Kerberos plutôt qu’en NTLM. - Deux voies d’intégration : les WebViews s’authentifient sans aucune ligne de code, les requêtes HTTP natives demandent un appel pour obtenir le jeton et un en-tête.
- Les variantes silencieuses fournissent les jetons aux workers d’arrière-plan et aux adaptateurs de synchronisation sans jamais afficher d’interface.
- La configuration est poussée via les configurations gérées, donc cela fonctionne avec toutes les principales plateformes MDM/EMM/UEM.
Microsoft démantèle l’authentification héritée pièce par pièce. Les événements d’audit NTLM sont arrivés avec Windows 11 24H2 et Server 2025, le single sign-on NTLMv1 sera bloqué en octobre 2026 (KB5066470), et le NTLM réseau disparaîtra entièrement avec la prochaine version Windows Server LTSC. Nous avons expliqué ce que cette dépréciation signifie pour les flottes mobiles dans le plan de Microsoft pour désactiver NTLM, et son nettoyage jumeau, la suppression de RC4 dans Kerberos, a déjà atteint son point de non-retour ce mois-ci.
Le côté serveur de cette migration est bien documenté. Le côté client est là où les équipes mobiles se retrouvent bloquées : chaque application Android interne qui répond encore à un défi NTLM, que ce soit via une WebView ou sa propre pile HTTP, doit commencer à envoyer des jetons de négociation Kerberos à la place. Les utilisateurs n’accepteront pas l’alternative, qui consiste à taper des mots de passe de domaine sur des téléphones. Cet article détaille comment combler cet écart avec le Hypergate SDK : ce qu’il fait, comment le configurer, et laquelle de ses méthodes de requête utiliser selon le cas.
Ce que fait réellement le SDK
Le SDK est la brique côté application d’un flux de single sign-on Kerberos. L’identité Kerberos de l’utilisateur réside dans une application d’authentification Kerberos sur l’appareil, comme Hypergate Authenticator, exposée à travers le framework de comptes standard d’Android. Quand votre application doit appeler un service kerberisé, le SDK demande à ce compte un jeton de négociation SPNEGO pour le nom de principal du service (par exemple [email protected]) et vous le renvoie sous forme de chaîne. Vous le placez dans l’en-tête Authorization: Negotiate et la requête est authentifiée.
Votre application ne voit jamais de mot de passe et ne stocke jamais d’identifiants. Tout ce qu’elle fait, c’est demander des jetons. C’est aussi ce qui en fait le point d’atterrissage naturel pour une migration hors de NTLM : la conception de NTLM repose sur des réponses à des défis dérivées du mot de passe, exactement la matière que les attaquants relaient et cassent, alors qu’un jeton de négociation ne contient aucune matière de mot de passe. Quels serveurs ont même le droit de recevoir des jetons n’est pas décidé dans le code non plus : l’informatique le contrôle de façon centralisée via une liste d’autorisation dans une configuration gérée.
Figure 1 : les applications hybrides et WebView sont prêtes après la configuration. Les applications natives ajoutent un appel de jeton par requête.
Configuration : une dépendance, une entrée de manifeste
Ajoutez le SDK depuis Maven Central au build.gradle de votre application (vérifiez Maven Central pour la dernière version) :
dependencies {
implementation "com.hypergate:sdk:1.6.0"
}
Si votre application ne définit pas ses propres restrictions d’application, référencez le fichier de restrictions du SDK dans votre AndroidManifest.xml :
<application>
<meta-data
android:name="android.content.APP_RESTRICTIONS"
android:resource="@xml/hypergate_sdk_restrictions" />
</application>
Si vous livrez déjà vos propres restrictions, copiez plutôt les entrées de hypergate_sdk_restrictions.xml dans votre fichier. Dans les deux cas, votre application expose désormais des configurations gérées que l’informatique définit dans la console EMM :
- Type de compte pour l’authentification HTTP Negotiate : quel type de compte répond aux défis d’authentification. Pour Hypergate, c’est
ch.papers.hypergate. - Liste d’autorisation des serveurs d’authentification : quels serveurs peuvent demander des jetons. Soit un joker (
*), soit une liste explicite de domaines. - Si l’authentification NTLMv2 est activée : un interrupteur de repli pour la WebView, sans rapport avec Hypergate lui-même. Si votre objectif est une application sans NTLM, laissez-le désactivé pour que la WebView ne réponde qu’aux défis Negotiate.
Cette liste d’autorisation centrale mérite qu’on s’y arrête : elle signifie que la politique de sécurité voyage avec la couche de gestion des appareils, pas avec les versions de l’application. Resserrer la liste des serveurs qui reçoivent des jetons ne vous oblige jamais à livrer une mise à jour.
Voie 1 : les WebViews, sans code
Si votre application est hybride (Cordova, Capacitor, ou similaire) ou affiche des services internes dans une WebView, vous avez déjà terminé. Avec la dépendance et les restrictions en place, chaque WebView de votre projet répond aux défis HTTP Negotiate de façon transparente, pour les chargements de page comme pour les appels AJAX. Il n’y a aucun intercepteur à écrire ni aucun jeton à gérer : l’utilisateur ouvre l’écran et il est connecté.
Pour Cordova en particulier, il existe un plugin prêt à l’emploi et une application d’exemple. Le seul cas où la magie de la WebView ne s’applique pas : une application hybride qui effectue ses requêtes HTTP via un plugin natif plutôt que via la pile WebView. Ce plugin est un client natif, il suit donc la voie 2.
Voie 2 : les requêtes de jeton natives
Pour les appels HTTP natifs, vous demandez un jeton vous-même. L’API est une méthode en quatre variantes, selon deux axes : synchrone contre asynchrone, et normale contre silencieuse. Les variantes normales prennent une Activity et peuvent afficher une interface si une interaction utilisateur est nécessaire, par exemple un sélecteur de compte ou un écran de consentement. Les variantes silencieuses prennent un simple Context, n’affichent jamais d’interface, et échouent à la place, ce qui est exactement ce que vous voulez dans un worker ou un adaptateur de synchronisation.
| Méthode | Bloquante | Prend | Peut afficher une interface | Appelant typique |
|---|---|---|---|---|
requestTokenSync | oui | Activity | oui | intercepteur sur un thread d’arrière-plan |
requestTokenAsync | non | Activity | oui | flux pilotés par l’interface |
requestTokenSilentlySync | oui | Context | jamais | WorkManager, adaptateurs de synchronisation |
requestTokenSilentlyAsync | non | Context | jamais | gestionnaires de push, services |
L’appel synchrone tient en une ligne :
val token = Hypergate.requestTokenSync(activity, "[email protected]")
// or from a background component, without any UI:
val token = Hypergate.requestTokenSilentlySync(context, "[email protected]")
La variante asynchrone livre le jeton ou l’exception à des callbacks :
Hypergate.requestTokenAsync(activity, "[email protected]",
{ negotiateToken -> Log.d("TOKEN", negotiateToken) },
{ exception -> Log.d("ERROR", exception.message) })
En pratique, la plupart des applications enveloppent l’appel de jeton une fois et n’y pensent plus. Avec OkHttp, cette enveloppe est un intercepteur :
internal class HypergateOkHttpInterceptor(
private val activity: Activity
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val token = Hypergate.requestTokenSync(
activity,
"HTTP/${request.url.host}"
)
val authenticatedRequest = request.newBuilder()
.addHeader("Authorization", "Negotiate ${token}")
.build()
return chain.proceed(authenticatedRequest)
}
}
val client = OkHttpClient.Builder()
.addInterceptor(HypergateOkHttpInterceptor(activity))
.build()
Chaque requête qui passe par ce client est désormais authentifiée. Le même schéma s’applique à Volley (construisez la carte des en-têtes dans getHeaders() et renvoyez-la) ou à n’importe quelle autre pile HTTP : demander le jeton, définir l’en-tête, envoyer. Si votre application transportait auparavant une bibliothèque NTLM ou du code de défi-réponse écrit à la main pour ces appels, cet intercepteur est ce qui le remplace.
Au-delà des bases : bundles, allers-retours, aides de compte
Les méthodes requestToken* ne renvoient que la chaîne du jeton, ce qui couvre le cas courant. Si vous avez besoin du résultat complet d’AccountManager, les contreparties requestTokenBundle* renvoient le Bundle brut, avec le jeton sous AccountManager.KEY_AUTHTOKEN. Les variantes bundle acceptent aussi deux paramètres supplémentaires pour les serveurs qui négocient sur plusieurs allers-retours : incomingAuthToken, le jeton que le serveur a renvoyé à l’étape précédente, et spnegoContext, un identifiant opaque qui transporte l’état de négociation entre les appels.
val bundle = Hypergate.requestTokenBundleSync(
activity, "[email protected]", incomingAuthToken, spnegoContext
)
val token = bundle.getString(AccountManager.KEY_AUTHTOKEN, "")
Quelques aides complètent l’API pour construire un onboarding sensé :
// true if a Hypergate account is present on the device
Hypergate.hasAccount(context)
// all Hypergate accounts (honors the managed configuration)
val accounts: Array<Account> = Hypergate.getAccounts(context)
// system intent to let the user pick or add an account
startActivity(Hypergate.getAccountChooserIntent(context))
Vérifiez hasAccount() au démarrage : s’il renvoie false, l’appareil n’est pas enrôlé ou l’authenticator n’est pas encore provisionné, et vous pouvez afficher un message utile au lieu de laisser la première requête échouer.
Figure 2 : choisir la bonne variante. Le code d’arrière-plan prend les méthodes silencieuses, les négociations à plusieurs étapes prennent les méthodes bundle, tout le reste prend la paire par défaut.
Gestion des erreurs
Tous les callbacks d’échec livrent une HypergateException qui porte deux propriétés : un code numérique sur lequel votre application peut brancher, et un message verbeux en anglais pour les logs. Le premier que vous rencontrerez est le code 101, « no accounts found ». Il ne signifie généralement pas que l’appareil n’a aucun compte Hypergate ; il signifie que le nom de package de votre application est absent de la liste de découvrabilité dans la configuration gérée Hypergate, donc le compte est invisible pour votre application. Ajoutez le nom de package dans la console EMM et le même appel réussit.
Où cela vous laisse
Chaque date butoir de l’authentification héritée aboutit au même endroit : Kerberos avec AES et, de plus en plus, des certificats au lieu de mots de passe. Y amener vos applications Android se résume à une petite surface d’intégration : une dépendance, une entrée de manifeste, et soit rien du tout (WebViews), soit un appel de jeton par requête (natif). La gestion des clés et la négociation des tickets restent à l’intérieur de l’authenticator, là où elles doivent être. Votre application demande des jetons et l’informatique contrôle la politique via l’EMM. Quand le blocage NTLMv1 d’octobre et le basculement LTSC arriveront, vos applications seront déjà du bon côté. Le code source du SDK et la documentation complète de l’API se trouvent dans le dépôt GitHub.
Vous migrez vos applications hors de NTLM ?
Hypergate Authenticator fournit l’identité Kerberos que vos applications consomment via ce SDK, sur Android et iOS gérés, avec tous les principaux EMM et aucun NTLM nulle part sur le chemin. Parlons de votre migration hors de l’authentification héritée.



