Si vous possédez un iPhone, vous connaissez sûrement l’application Wallet !

L’application Wallet regroupe différents pass similaires à des cartes de fidélités, billets de train/avion, ou encore Apple Pay, et permet ainsi d’accéder facilement et rapidement à ces éléments depuis notre téléphone. Cette fonctionnalité est principalement compatible avec les appareils Apple, mais on trouve aujourd’hui sur Android quelques applications qui prennent en charge les pass Wallet.

On retrouve généralement la fonctionnalité des pass Wallet au sein d’une application iOS, sous forme du pictogramme ci-dessous. Il est cependant intéressant de savoir que les applications de mail ou encore Safari sont aussi capables de les intégrer directement dans l’application Wallet. Cela rend possible l’utilisation de la fonctionnalité sans avoir forcément besoin d’une application sur le store. C’est ce deuxième cas, un peu moins fréquent mais néanmoins utile, que nous allons traiter dans cet article.

 

L’usage typique de cette approche nous intéresse, par exemple, lors de la création d’événements avec inscription chez Cellenza. Lorsqu’une personne s’inscrit sur notre site pour participer à un événement, un mail de confirmation lui est envoyé, et nous pouvons y ajouter un pass Wallet que l’utilisateur peut intégrer à son téléphone (à condition que celui-ci puisse lire le pass). Cela permet au final de continuer l’expérience utilisateur après l’inscription.

 

Anatomie d’un Pass Wallet

Pour faire simple, un pass wallet est une archive, avec un format particulier nommé pkpass. On peut voir très facilement ce que contient un pkpass en renommant le fichier original .pkpass en .zip, qu’il suffit ensuite de décompresser pour révéler son contenu.

De manière générale, on retrouve dans le dossier décompressé plusieurs images, un fichier pass.json qui va décrire le pass, un fichier manifest.json, qui va contenir les hashs de tous les éléments du dossier, ainsi qu’un fichier nommé “signature“.

Apple propose 5 templates de pass différents, qui sont pensés pour s’adapter à plusieurs contextes :

Pour chaque template, un certain nombre de customisations est possible. Attention tout de même, car cela reste une technologie Apple, la customisation est soumise à des contraintes.

Dans cet article, l’exemple de pass choisi sera basé sur le template du ticket d’événement, et il affichera des informations sur un événement Cellenza.

Si on souhaite créer un Pass Wallet, Apple précise que nous sommes responsables de deux points : la distribution du pass, ainsi que son expiration. L’étape intermédiaire dans le cycle de vie d’un pass, la gestion du pass, est gérée par l’application Wallet.

 

La sécurité avant tout

Un pass qui a pour but d’être sur l’application Wallet doit être sûr pour l’utilisateur, il doit donc être obligatoirement signé. iOS et MacOS, qui peuvent tous deux lire un fichier pkpass, vérifient l’intégrité du pass avant de l’afficher à l’utilisateur. Cela permet de certifier que le pass n’a pas été modifié par un tiers. Dans une archive .pkpass le rôle de sécurité est assuré par le fichier “signature” mentionné plus haut.

Avant de nous lancer dans la partie code pour générer notre pass Wallet, il va falloir avant tout, trois armes qui serviront à la signature :

  • Le certificat de confiance pour les développeurs, qui peut être téléchargé ici.
  • Un identifiant pour Pass lié à notre compte développeur Apple, qui se crée sur la plateforme du compte développeur Apple.
    Plus d’infos ici pour savoir comment créer l’identifiant et trouver l’identifiant d’équipe.
  • Un certificat de signature, qui soit aura déjà été associé à l’identifiant de Pass, soit devra être généré. Toutes les étapes sont spécifiées sur la plateforme développeur Apple. Plus d’infos ici.

L’identifiant du Pass ainsi que l’identifiant d’équipe seront à renseigner dans le fichier pass.json, et les deux certificats seront utilisés dans le code lors de l’étape de signature automatique du pass.

Les prochaines questions qui se posent sont : où hébergera-t-on le code du générateur de Pass ? Comment sera-t-il appelé ?

Azure vient à notre rescousse pour cela, car parmi le panel de services proposés par celui-ci, se trouvent les Azure Functions, qui vont nous intéresser pour notre cas.

 

Générer le pkpass dans une Azure Function

Kezaco une Azure Function ?

Une Azure Function est un morceau de code hébergé sur Azure qui s’exécute en réponse à un évenement, qui prend en paramètre une ou plusieurs entrées et produit une ou plusieurs sorties. C’est ce qu’on appelle du “serverless“.

Le code reste bien sûr hébergé sur un serveur, mais tout, de la gestion du serveur à la plateforme d’exécution ainsi que l’orchestration de la fonction, est pris en charge par Azure. Seul le code de la fonction est à la charge du développeur.

 

Pourquoi une Azure Function ?

L’opération de génération de pkpass est une opération ponctuelle, en réponse à un événement, ce qui cadre bien avec le modèle de facturation et d’utilisation d’une Azure Function.

En effet, l’Azure Function n’est facturée qu’à l’appel, pendant le temps nécessaire au traitement de celui-ci. De plus, une Azure Function est simple à mettre en place.

 

Quels choix pour le paramétrage de l’Azure Function ?

Pour notre cas, nous avons choisi d’exécuter l’Azure Function en réponse à un appel HTTP. Par conséquent, l’entrée sera la requête HTTP. La sortie la réponse HTTP contenant le pkpass généré.

Selon le cas de figure, il serait possible d’avoir différentes utilisations. Par exemple : une entrée sous la forme d’un événement dans un topic Service Bus généré par un micro service d’inscription à l’événement. Les sorties peuvent elles aussi êtres diverses, comme un mail envoyé par SendGrid contenant le pkpass en pièce jointe, ou l’archivage de celui-ci dans un stockage Azure Storage.

Pour le choix du modèle d’exécution nous choisissons une facturation à l’événement, puisque le premier million d’exécutions par mois est offert.

 

Comment créer une Azure Function ?

La création de l’environnement d’exéctution Azure Function ainsi qu’une fonction peut se faire à l’aide de ce tutoriel.

Dans notre exemple, nous avons choisi d’utiliser une Azure Function en C# class library. La documentation pour ce concept est disponible ici.

 

Mangez du code ! Et des pommes

 

 

Traitement HTTP (réception de la requête, émission de la réponse)

En début de méthode on reçoit un HTTPRequest qui est l’objet qui matérialise le trigger. Dans cette requête on peut avoir des paramètres dans le body ou la queryString, une autorisation, etc. Nous pourrions, par exemple, recevoir de façon dynamique les informations de l’événement pour lequel nous voulons créer un pass. En fin de méthode, on retourne un HTTPResult qui contient le zip du pass, un statut HTTP, ainsi qu’un entête pour nommer le fichier à télécharger.

 

Création du zip

On utilise une ZipArchive dans laquelle sont ajoutées des ZipArchiveEntry qui correspondent au contenu du pkpass. Pour chaque fichier on crée d’abord son ZipArchiveEntry relié à l’archive, avec le nom du fichier souhaité, et on va ensuite écrire dans cet objet.

 

Ajout du pass.json

C’est dans le pass.json que sont renseignées les principales informations du pkpass. Pour remplir le pass.json il suffit de créer un objet à partir d’une classe qui aura les champs requis dans le pass.json, avec les valeurs souhaitées, on sérialise cet objet, puis on écrit dans le Stream de la ZipArchiveEntry.

S’ajoute à cela un calcul du hash du fichier, dont le résultat est passé en retour de la méthode, pour être utilisé plus tard dans le manifest.json

 

Ajout des images

Ici, même principe que pour le pass.json, une ZipArchiveEntry est créé, et dans une méthode à part dans laquelle on précise également le lien du fichier (qui dans notre exemple se trouve dans le dossier Assets), l’image en question est lue sous forme de Stream, son hash est calculé, le contenu du Stream est écrit dans la ZipArchiveEntry, et le hash est retourné.

 

Ajout du manifest et checksum

Pour la création du manifest, un JObject est d’abord créé avec toutes les JProperty qui devront être présentes dans le fichier. Comme pour les étapes précédentes une ZipArchiveEntry sous le nom de manifest.json est créé au sein de la ZipArchive, et la méthode CreateManifestJson va transformer le JObject en string pour ensuite l’écrire dans la ZipArchiveEntry. Cette méthode va retourner un tableau de bytes qui contient le contenu du fichier manifest.json.

A ce moment-là, la configuration est terminée, il ne reste plus qu’à signer le manifest, et à créer physiquement le zip.

 

Ajout de la signature

Dans la solution actuelle, un fichier .pfx (ou .p12) est inclu dans la solution du projet, dans le même dossier que les images. Ce fichier contient toutes les informations nécessaires pour signer un fichier, notamment le certificat pour signer le pkpass et sa clé privée, ainsi que la chaîne d’autorité de certification. Il serait possible de faire la même opération de signature avec l’ensemble de ces certificats à part, mais cette solution évite de manipuler plusieurs fichiers avec leurs mots de passe respectifs.

Un objet SignedCms est instancié avec le manifest passé sous forme de tableau de bytes, ainsi qu’un Oid bien précis, qui signifie que le contenu à signer est un pass.

Après quelques configurations, on utilise le .pfx pour signer le SignedCms créé, et on écrit le contenu de l’objet dans le fichier signature.

 

Publication de l’Azure Function

Une fois le code de notre Function prêt, la publication peut se dérouler. Il est possible de configurer les différents AppSettings dans le portail et de récupérer une clef de sécurité (selon le mode de sécurité choisi) à passer en paramètre dans l’url finale.

La function est prête à être exécutée, et voici le résultat !

Vous pouvez retrouver le code sur Github.

 

Conclusion

Dans cet article, nous avons vu l’anatomie d’un pass wallet pour iOS, comment le créer en C# et utiliser une Azure Function pour ceci. Bien que le code soit intéressant pour un PoC, il comporte toutefois un point négatif d’un point de vue sécurité pour passer en production.
En effet, dans l’exemple la clef privée se trouve parmis les Assets de l’application et bien que protégée par mot de passe, il est déconseillé de la laisser en liberté. Sous Windows, il existe par exemple le magasin de certificats pour sécuriser cette ressource.
Dans l’article suivant, nous verrons comment sécuriser la gestion des certificats et des secrets sur Azure afin que la sécurité soit garantie et notre Azure Function opérationelle pour la production !
Article co-écrit avec Nathanaël Marchand.
arbre décisionnel