Acquisire un token di accesso (Python)

Questo esempio illustra come chiamare uno script Python esterno per ottenere un token OAuth2. Un token di accesso OAuth2 valido è richiesto dall'implementazione del delegato di autenticazione.

Prerequisiti

Per eseguire l'esempio:

  • Installare Python 3.10 o versione successiva.
  • Implementare utils.h/cpp nel progetto.
  • Auth.py deve essere aggiunto al progetto ed essere presente nella stessa directory dei file binari in fase di compilazione.
  • Completare la configurazione e la configurazione di Microsoft Information Protection SDK (MIP). Tra le altre attività, registrare l'applicazione client nel tenant di Microsoft Entra. Microsoft Entra ID fornisce un ID applicazione, noto anche come ID client, usato nella logica di acquisizione del token.

Questo codice non è destinato all'uso in produzione. Può essere usato solo per lo sviluppo e la comprensione dei concetti di autenticazione. L'esempio è multipiattaforma.

sample::auth::AcquireToken()

Nell'esempio di autenticazione semplice è stata illustrata una funzione semplice AcquireToken() che non ha preso parametri e ha restituito un valore di token hardcoded. In questo esempio si esegue l'overload di AcquireToken() per accettare i parametri di autenticazione e chiamare uno script Python esterno per restituire il token.

auth.h

In auth.h viene AcquireToken() eseguito l'overload e la funzione di overload e i parametri aggiornati sono i seguenti:

//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.
    }
}

I primi tre parametri vengono forniti dall'input dell'utente o hardcoded nell'applicazione. Gli ultimi due parametri vengono forniti dall'SDK al delegato di autenticazione.

auth.cpp

In auth.cpp si aggiunge la definizione della funzione di overload, quindi si definisce il codice necessario per chiamare lo script Python. La funzione accetta tutti i parametri forniti e li passa allo script Python. Lo script viene eseguito e restituisce il token in formato stringa.

#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;
    }
    }
}

Python Script

Questo script acquisisce i token di autenticazione direttamente tramite Microsoft Authentication Library (MSAL) per Python. Questo codice è incluso solo come mezzo per acquisire i token di autenticazione da usare dalle app di esempio e non è destinato all'uso nell'ambiente di produzione. Lo script funziona solo nei tenant che supportano l'autenticazione con nome utente/password precedente. L'autenticazione basata su certificati o MFA non è supportata tramite questo script.

Nota

Prima di eseguire questo esempio, è necessario installare MSAL per Python eseguendo uno dei comandi seguenti:

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:])

Aggiornare AcquireOAuth2Token

Aggiornare infine la AcquireOAuth2Token funzione in AuthDelegateImpl per chiamare la funzione di overload AcquireToken . Gli URL delle risorse e dell'autorità vengono ottenuti leggendo challenge.GetResource() e challenge.GetAuthority(). L'oggetto OAuth2Challenge viene passato al delegato di autenticazione quando viene aggiunto il motore. Questo lavoro viene eseguito dall'SDK e non richiede alcun lavoro aggiuntivo da parte dello sviluppatore.

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;
}

engine Quando viene aggiunto , l'SDK chiama la funzione 'AcquireOAuth2Token, passando la richiesta di verifica, eseguendo lo script Python, ricevendo un token, quindi presentando il token al servizio.