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

Cet exemple montre comment appeler un script de Python externe pour obtenir un jeton OAuth2. Un jeton d’accès OAuth2 valide est requis par l’implémentation du délégué d’authentification.

Prerequisites

Pour exécuter l’exemple :

  • Installez Python version 3.10 ou ultérieure.
  • Implémentez utils.h/cpp dans votre projet.
  • Auth.py doit être ajouté à votre projet et se trouver dans le même répertoire que les fichiers binaires lors de la génération.
  • Terminez la configuration et l’installation du SDK Microsoft Information Protection (MIP). Parmi d’autres tâches, vous enregistrez votre application client dans votre locataire Entra Microsoft. Microsoft Entra ID fournit un ID d’application, également appelé ID client, utilisé dans votre logique d’acquisition de jeton.

Ce code n’est pas destiné à une utilisation en production. Elle peut uniquement être utilisée pour le développement et la compréhension des concepts d’authentification. L’exemple est multiplateforme.

sample::auth::AcquireToken()

Dans l’exemple d’authentification simple, nous avons démontré une fonction simple AcquireToken() qui n’a pris aucun paramètre et retourné une valeur de jeton codé en dur. Dans cet exemple, nous surchargeons AcquireToken() pour accepter les paramètres d’authentification et appeler un script de Python externe pour retourner le jeton.

auth.h

Dans auth.h, AcquireToken() est surchargé et 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.
    }
}

Les trois premiers paramètres sont fournis par l’entrée utilisateur ou codées en dur dans votre application. Les deux derniers paramètres sont fournis par le Kit de développement logiciel (SDK) au délégué d’authentification.

auth.cpp

Dans auth.cpp, nous ajoutons la définition de fonction surchargée, puis définissons le code nécessaire pour appeler 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 de 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 Python

Ce script acquiert des jetons d’authentification directement via Microsoft Authentication Library (MSAL) pour Python. Ce code est inclus uniquement comme moyen d’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’ancienne authentification par nom d’utilisateur/mot de passe. L’authentification MFA ou basée sur des certificats n’est pas prise en charge via ce script.

Note

Avant d’exécuter cet exemple, vous devez installer 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. Les URL de ressource et d’autorité sont obtenues par lecture challenge.GetResource() et challenge.GetAuthority(). Le OAuth2Challenge est transmis au délégué d’authentification lorsque le moteur est ajouté. Ce travail est effectué par le Kit de développement logiciel (SDK) et ne nécessite aucun travail supplémentaire de la part 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 engine est ajouté, le SDK appelle la fonction `AcquireOAuth2Token`, lui transmet la question d’authentification, exécute le script Python, reçoit un jeton, puis présente celui-ci au service.