Acquérir un jeton d’accès (Python)

Cet exemple montre comment appeler un script de Python externe pour obtenir un jeton OAuth 2.0. L’implémentation du délégué d’authentification nécessite un jeton d’accès OAuth 2.0 valide.

Prerequisites

Pour exécuter l’exemple :

  • Installez Python version 3.10 ou ultérieure.
  • Implémentez utils.h/cpp dans votre projet.
  • Ajoutez auth.py à votre projet, dans le même répertoire que les binaires lors de la compilation.
  • Terminez la configuration et l’installation du SDK Microsoft Information Protection (MIP). Entre autres tâches, vous enregistrez votre application cliente dans votre locataire Microsoft Entra. Microsoft Entra ID fournit un ID d’application, également appelé ID client, pour votre logique d’acquisition de jetons.

Ce code n’est pas destiné à une utilisation en production. Utilisez-le uniquement pour le développement et pour comprendre les concepts d’authentification. L’exemple est multiplateforme.

sample::auth::AcquireToken()

L’exemple d’authentification simple illustre une fonction simple AcquireToken() qui ne prend aucun paramètre et retourne une valeur de jeton codé en dur. Cet exemple surcharge AcquireToken() pour accepter des paramètres d’authentification et appeler un script Python externe afin de renvoyer le jeton.

auth.h

Dans auth.h, AcquireToken() est surchargé. La fonction surchargée et les paramètres mis à jour sont les suivants :

//auth.h
#include <string>

namespace sample {
  namespace auth {
    std::string AcquireToken(
        const std::string& userName, //A string value containing the user's UPN.
        const std::string& password, //The user's password in plaintext
        const std::string& clientId, //The Azure AD client ID (also known as Application ID) of your application.
        const std::string& resource, //The resource URL for which an OAuth2 token is required. Provided by challenge object.
        const std::string& authority); //The authentication authority endpoint. Provided by challenge object.
    }
}

L’entrée utilisateur ou votre application fournit les trois premiers paramètres. Le Kit de développement logiciel (SDK) fournit les deux derniers paramètres au délégué d’authentification.

auth.cpp

Le fichier auth.cpp ajoute la définition de fonction surchargée, puis définit le code qui appelle le script Python. La fonction accepte tous les paramètres fournis et les transmet au script Python. Le script s’exécute et retourne le jeton au format chaîne.

#include "auth.h"
#include "utils.h"

#include <fstream>
#include <functional>
#include <memory>
#include <string>

using std::string;
using std::runtime_error;

namespace sample {
    namespace auth {

    //This function implements token acquisition in the application by calling an external Python script.
    //The Python script requires username, password, clientId, resource, and authority.
    //Username, Password, and ClientId are provided by the user/developer
    //Resource and Authority are provided as part of the OAuth2Challenge object that is passed in by the SDK to the AuthDelegate.
    string AcquireToken(
        const string& userName,
        const string& password,
        const string& clientId,
        const string& resource,
        const string& authority) {

    string cmd = "python";
    if (sample::FileExists("auth.py"))
        cmd += " auth.py -u ";

    else
        throw runtime_error("Unable to find auth script.");

    cmd += userName;
    cmd += " -p ";
    cmd += password;
    cmd += " -a ";
    cmd += authority;
    cmd += " -r ";
    cmd += resource;
    cmd += " -c ";
    // Replace <application-id> with the Application ID provided during your Azure AD application registration.
    cmd += (!clientId.empty() ? clientId : "<application-id>");

    string result = sample::Execute(cmd.c_str());
    if (result.empty())
        throw runtime_error("Failed to acquire token. Ensure Python is installed correctly.");

    return result;
    }
    }
}

Script en Python

Ce script acquiert directement des jetons d’authentification à l’aide de Microsoft Authentication Library (MSAL) pour Python. Ce code est inclus uniquement pour acquérir des jetons d’authentification à utiliser par les exemples d’applications et n’est pas destiné à être utilisé en production. Le script fonctionne uniquement sur les locataires qui prennent en charge l’authentification par nom d’utilisateur/mot de passe. Le script ne prend pas en charge l’authentification multifacteur (MFA) ou l’authentification basée sur des certificats.

Note

Avant d’exécuter cet exemple, installez MSAL pour Python en exécutant l’une des commandes suivantes :

pip install msal
pip3 install msal
import getopt
import sys
import json
import re
from msal import PublicClientApplication

def printUsage():
  print('auth.py -u <username> -p <password> -a <authority> -r <resource> -c <clientId>')

def main(argv):
  try:
    options, args = getopt.getopt(argv, 'hu:p:a:r:c:')
  except getopt.GetoptError:
    printUsage()
    sys.exit(-1)

  username = ''
  password = ''
  authority = ''
  resource = ''

  clientId = ''
    
  for option, arg in options:
    if option == '-h':
      printUsage()
      sys.exit()
    elif option == '-u':
      username = arg
    elif option == '-p':
      password = arg
    elif option == '-a':
      authority = arg
    elif option == '-r':
      resource = arg
    elif option == '-c':
      clientId = arg

  if username == '' or password == '' or authority == '' or resource == '' or clientId == '':
    printUsage()
    sys.exit(-1)

  # ONLY FOR DEMO PURPOSES AND MSAL FOR PYTHON
  # This shouldn't be required when using proper auth flows in production.  
  if authority.find('common') > 1:
    authority = authority.split('/common')[0] + "/organizations"
   
  app = PublicClientApplication(client_id=clientId, authority=authority)  
  
  result = None  

  if resource.endswith('/'):
    resource += ".default"    
  else:
    resource += "/.default"
  
  # *DO NOT* use username/password authentication in production system.
  # Instead, consider auth code flow and using a browser to fetch the token.
  result = app.acquire_token_by_username_password(username=username, password=password, scopes=[resource])
  print(result['access_token'])

if __name__ == '__main__':  
  main(sys.argv[1:])

Mettre à jour AcquireOAuth2Token

Enfin, mettez à jour la fonction AcquireOAuth2Token dans AuthDelegateImpl afin d’appeler la fonction surchargée AcquireToken. Lisez challenge.GetAuthority() et challenge.GetResource() pour obtenir les URL de ressource et d’autorité. Le kit de développement logiciel (SDK) transmet OAuth2Challenge au délégué d’authentification lorsqu’il ajoute le moteur. Ce comportement du Kit de développement logiciel (SDK) ne nécessite aucun travail supplémentaire du développeur.

bool AuthDelegateImpl::AcquireOAuth2Token(
    const mip::Identity& /*identity*/,
    const OAuth2Challenge& challenge,
    OAuth2Token& token) {

    //call our AcquireToken function, passing in username, password, clientId, and getting the resource/authority from the OAuth2Challenge object
    string accessToken = sample::auth::AcquireToken(mUserName, mPassword, mClientId, challenge.GetResource(), challenge.GetAuthority());
    token.SetAccessToken(accessToken);
    return true;
}

Lorsque le SDK ajoute le engine, il appelle la fonction AcquireOAuth2Token. La fonction passe dans le défi, exécute le script Python, reçoit un jeton et présente le jeton au service.