Adquirir un token de acceso (Python)

En este ejemplo se muestra cómo llamar a un script de Python externo para obtener un token de OAuth2. La implementación del delegado de autenticación requiere un token de acceso OAuth2 válido.

Requisitos previos

Para ejecutar el ejemplo siguiente:

  • Instale Python 2.7 o posterior.
  • Implemente utils.h/cpp en el proyecto.
  • Auth.py debe agregarse al proyecto y existir en el mismo directorio que los archivos binarios en la compilación.
  • Configuración y configuración completa del SDK (MIP). Entre otras tareas, registrará la aplicación cliente en el espacio empresarial Azure Active Directory (Azure AD). Azure AD proporcionará un id. de aplicación, también conocido como id. de cliente, que se usa en la lógica de adquisición de tokens.

Este código no está diseñado para uso de producción. Solo se puede usar para el desarrollo y la comprensión de conceptos de autenticación. El ejemplo es multiplataforma.

ejemplo::auth::AcquireToken()

En el ejemplo de autenticación simple, demostramos una función sencilla que no tomaba ningún parámetro y devuelve un valor de AcquireToken() token codificado de forma automática. En este ejemplo, sobrecargaremos AcquireToken() para aceptar parámetros de autenticación y llamaremos a un script de Python externo para devolver el token.

auth.h

En auth.h, está sobrecargado y la función sobrecargada y los parámetros AcquireToken() actualizados son los siguientes:

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

Los tres primeros parámetros se proporcionan mediante entrada del usuario o codificada de forma codificada en la aplicación. El SDK proporciona los dos últimos parámetros al delegado de autenticación.

auth.cpp

En auth.cpp, agregamos la definición de función sobrecargada y, a continuación, definimos el código necesario para llamar al script de Python. La función acepta todos los parámetros proporcionados y los pasa al script de Python. El script ejecuta y devuelve el token en formato de cadena.

#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

Este script adquiere tokens de autenticación directamente a través de ADAL para Python. Este código se incluye solo como un medio para adquirir tokens de autenticación para su uso por las aplicaciones de ejemplo y no está destinado a su uso en producción. El script solo funciona con inquilinos que admiten autenticación http de nombre de usuario o contraseña antiguos sin formato. Se producirá un error en la autenticación basada en certificados o MFA.

Nota

Antes de ejecutar este ejemplo, debe instalar ADAL para Python ejecutando uno de los siguientes comandos:

pip install adal
pip3 install adal
import getopt
import sys
import json
import re
from adal import AuthenticationContext

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)

  # Find everything after the last '/' and replace it with 'token'
  if not authority.endswith('token'):
    regex = re.compile('^(.*[\/])')
    match = regex.match(authority)
    authority = match.group()
    authority = authority + username.split('@')[1]

  auth_context = AuthenticationContext(authority)
  token = auth_context.acquire_token_with_username_password(resource, username, password, clientId)
  print(token["accessToken"])

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

Actualizar AcquireOAuth2Token

Por último, actualice AcquireOAuth2Token la función para llamar a la función AuthDelegateImplAcquireToken sobrecargada. Las direcciones URL de recursos y autoridad se obtienen mediante lectura challenge.GetResource() y challenge.GetAuthority() . Se OAuth2Challenge pasa al delegado de autenticación cuando se agrega el motor. Este trabajo lo realiza el SDK y no requiere ningún trabajo adicional por parte del desarrollador.

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

Cuando se agrega, el SDK llamará a la función "AcquireOAuth2Token, pasando el reto, ejecutando el script de Python, recibiendo un token y presentando el token al engine servicio.