Configuración de Azure AD y autenticación de Microsoft Graph

Aspose.Email for Java ofrece una integración completa con Microsoft Graph, permitiendo a los desarrolladores gestionar mensajes, contactos, calendarios y tareas de cuentas Microsoft 365. Esta guía te muestra cómo crear una aplicación Azure AD y configurar la autenticación para comenzar a programar con Aspose.Email GraphClient.

Antes de usar las API de Microsoft Graph con Aspose.Email, necesitas registrar una aplicación en Azure Active Directory (Azure AD) y configurar la autenticación. Esta página cubre:

  • Creando una aplicación Azure AD (proyecto).

  • Asignando los permisos necesarios de Microsoft Graph.

  • Generando credenciales (client ID, client secret, tenant ID).

  • Autenticando en Java usando proveedores de tokens de Aspose.Email.

Una vez completado, estarás listo para interactuar con Microsoft Graph desde tu aplicación Java.

1. Crear una aplicación Azure AD

Sigue estos pasos para registrar tu aplicación en el portal de Azure:

  1. Inicia sesión en el Portal de Azure.
  2. Navega a Azure Active DirectoryRegistros de aplicacionesNuevo registro.

todo:image_alt_text

  1. Introduce un Nombre para tu aplicación (p.ej., AsposeEmailGraphApp).
  2. Elige los tipos de cuenta compatibles:
    • Inquilino único (si solo tu organización lo usará)
    • Multinquilino (si varias organizaciones necesitan acceso)
  3. Opcionalmente, establece una URI de redireccionamiento (necesaria para autenticación interactiva o web).
  4. Haz clic en Registrar.

todo:image_alt_text

2. Crear client secret

  1. Después del registro, ve a Certificados y secretosNuevo client secret.
  2. Añade una descripción y el período de expiración.

todo:image_alt_text

  1. Copia el valor secreto generado - no lo volverás a ver.

Mantén el client secret seguro; es necesario para la autenticación de cliente confidencial.

Deberías ver la hoja de aplicaciones recién registradas.

todo:image_alt_text

3. Configurar permisos de Microsoft Graph

  1. Navega a Permisos de APIAgregar un permisoMicrosoft Graph.
  2. Elige el tipo de permisos: Delegado o Aplicación, según tu escenario.
  3. Añade los permisos requeridos para operaciones de Aspose.Email:
    • Contacts.ReadWrite – para gestionar contactos
    • Calendars.ReadWrite – para gestionar calendarios
    • Mail.ReadWrite – para leer y enviar mensajes
    • Tasks.ReadWrite – para gestionar tareas
  4. Haz clic en Conceder consentimiento de administrador si es necesario.

todo:image_alt_text

4. Permitir flujos de cliente público

Especifica si la aplicación es un cliente público. Adecuado para aplicaciones que usan flujos de concesión de tokens que no utilizan una URI de redireccionamiento.

todo:image_alt_text

5. Autenticación de Microsoft Graph

Métodos de Autenticación Compatibles en Aspose.Email

| Proveedor de Token | Caso de Uso | | ——————————– | ————————————————————————————— | | AzureConfidentialTokenProvider | Cliente confidencial (client ID + secret) para aplicaciones del lado del servidor | | AzureROPCConfiguration | Credenciales de Propietario de Recursos (usuario + contraseña) para escenarios no interactivos | | AzurePublicTokenProvider | Cliente público (inicio de sesión interactivo) | | AzureTokenProviderBase | Clase base para implementaciones de autenticación personalizadas |

Autenticar usando un Cliente Confidencial

Utilice el AzureConfidentialTokenProvider para autenticarse cuando tienes client ID, client secret y tenant ID:

AzureConfidentialTokenProvider provider = new AzureConfidentialTokenProvider(
    tenantId,
    clientId,
    clientSecret
);

IGraphClient client = GraphClient.getClient(provider, tenantId);
client.setResource(ResourceType.Users);
client.setResourceId(username);
client.setEndpoint("https://graph.microsoft.com");

Esto configura un IGraphClient totalmente autenticado listo para interactuar con Microsoft Graph.

Autenticar usando ROPC (Usuario y Contraseña)

Para escenarios donde tienes un nombre de usuario y contraseña, usa AzureROPCConfiguration:

AzureROPCConfiguration ropcConfig = new AzureROPCConfiguration(
    tenantId,
    clientId,
    clientSecret,
    username,
    password
);

IGraphClient client = GraphClient.getClient(ropcConfig, tenantId);
client.setResource(ResourceType.Users);
client.setResourceId(username);
client.setEndpoint("https://graph.microsoft.com");

Proveedores de Tokens Personalizados para Microsoft Graph

Aspose.Email for Java se integra con Microsoft Graph a través del IGraphClient interfaz. Para autenticar solicitudes, una implementación de la ITokenProvider es necesario. Aunque la mayoría de los desarrolladores usarán proveedores de autenticación incorporados, hay escenarios en los que podrías querer crear tu propio proveedor, por ejemplo, al trabajar con el flujo Resource Owner Password Credentials (ROPC).

1. Implementar ITokenProvider usando AzureROPCTokenProvider

Esta clase proporciona una implementación de ITokenProvider usando el flujo Azure Resource Owner Password Credentials (ROPC). El siguiente ejemplo es solo con fines de demostración. En producción, recomendamos usar flujos más seguros como credenciales de cliente o código de autorización con PKCE.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * Azure resource owner password credential (ROPC) token provider
 * https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc
 * https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth
 * https://portal.azure.com
 * https://developer.microsoft.com/en-us/graph/graph-explorer/#
 * token parser https://jwt.io
 * </p>
 */
class AzureROPCTokenProvider implements ITokenProvider {

    private static final String GRANT_TYPE = "password";

    private final String clientId;
    private final String clientSecret;
    private final String userName;
    private final String password;
    private final String tenant;
    private final String scope;

    private OAuthToken token;

    public AzureROPCTokenProvider(String tenant, String clientId, String clientSecret,
                                  String userName, String password, String[] scopeAr) {
        this.tenant = tenant;
        this.clientId = clientId;
        this.clientSecret = clientSecret;
        this.userName = userName;
        this.password = password;
        this.scope = joinToStr(scopeAr, " ");
    }

    public synchronized OAuthToken getAccessToken(boolean ignoreExistingToken) {
        if (this.token != null && !this.token.getExpired() && !ignoreExistingToken)
            return this.token;
        token = null;

        Map<String, String> tokenArgs = getToken();

        java.util.Calendar c = java.util.Calendar.getInstance();
        c.add(java.util.Calendar.SECOND, Integer.parseInt(tokenArgs.get("expires_in")));
        token = new OAuthToken(tokenArgs.get("access_token"), TokenType.AccessToken, c.getTime());
        return token;
    }

    public final OAuthToken getAccessToken() {
        return getAccessToken(false);
    }

    public void dispose() {
    }

    private String getEncodedParameters() {
        return "client_id=" + urlEncode(clientId) + "&scope=" + urlEncode(scope) + "&username=" + urlEncode(userName)
                + "&password=" + urlEncode(password) + "&grant_type="
                + urlEncode(GRANT_TYPE);
    }

    private String getUri() {
        if (tenant == null || tenant.trim().isEmpty())
            return "https://login.microsoftonline.com/common/oauth2/v2.0/token";
        else
            return "https://login.microsoftonline.com/" + tenant + "/oauth2/v2.0/token";
    }

    private Map<String, String> getToken() {
        try {
            HttpURLConnection connection = (HttpURLConnection) new URL(getUri()).openConnection();
            connection.setRequestMethod("POST");

            byte[] requestData = getEncodedParameters().getBytes(StandardCharsets.UTF_8);

            connection.setUseCaches(false);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            connection.setRequestProperty("Content-Length", "" + requestData.length);

            final OutputStream st = connection.getOutputStream();
            try {
                st.write(requestData, 0, requestData.length);
            } finally {
                st.flush();
                st.close();
            }

            connection.connect();

            if (connection.getResponseCode() >= HttpURLConnection.HTTP_BAD_REQUEST) {
                throw new IllegalAccessError("Operation failed: " + connection.getResponseCode() + "/" +
                        connection.getResponseMessage() + "\r\nDetails:\r\n{2}"
                        + readInputStream(connection.getErrorStream()));
            }

            String responseText = readInputStream(connection.getInputStream());

            Map<String, String> result = new HashMap<>();
            String[] fromJsonToKeyValue = responseText.replace("{", "").replace("}", "")
                    .replace("\"", "").replace("\r", "")
                    .replace("\n", "").split(",");
            for (String keyValue : fromJsonToKeyValue) {
                String[] pair = keyValue.split(":");
                String name = pair[0].trim().toLowerCase();
                String value = urlDecode(pair[1].trim());
                result.put(name, value);
            }

            return result;
        } catch (IOException e) {
            throw new IllegalAccessError(e.getMessage());
        }
    }

    static String urlEncode(String value) {
        try {
            return URLEncoder.encode(value, StandardCharsets.UTF_8.toString());
        } catch (UnsupportedEncodingException e) {
            throw new IllegalAccessError(e.getMessage());
        }
    }

    static String urlDecode(String value) {
        try {
            return URLDecoder.decode(value, StandardCharsets.UTF_8.toString());
        } catch (UnsupportedEncodingException e) {
            throw new IllegalAccessError(e.getMessage());
        }
    }

    static String readInputStream(InputStream is) {
        if (is == null)
            return "";

        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder result = new StringBuilder();
        String line;
        try {
            while ((line = reader.readLine()) != null) {
                result.append(line);
            }
        } catch (IOException e) {
            // ignore
        }
        return result.toString();
    }

    static String joinToStr(String[] arr, String sep) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            if (i > 0)
                sb.append(sep);
            sb.append(arr[i]);
        }
        return sb.toString();
    }
}

2. Crear un Objeto ITokenProvider

El IGraphClient interfaz es responsable de crear solicitudes, enviarlas a Microsoft Graph y manejar las respuestas. Para crear una instancia de IGraphClient, debes proporcionar una implementación de ITokenProvider. El proveedor de tokens autentica las solicitudes proporcionando un token de acceso OAuth válido.

El siguiente ejemplo de código demuestra cómo crear una implementación básica en línea de la ITokenProvider interfaz, que es necesaria para autenticar solicitudes de Microsoft Graph:

ITokenProvider tokenProvider = new ITokenProvider() {
    Date expirationDate = null;

    @Override
    public void dispose() {
        // Clean up resources if necessary
    }

    @Override
    public OAuthToken getAccessToken(boolean ignoreExistingToken) {
        // Retrieve an OAuth access token.
        // If ignoreExistingToken is true, always request a new token.
        // Otherwise, return the existing token if it is valid, or request a new one.
        return null;
    }

    @Override
    public OAuthToken getAccessToken() {
        // Return a valid OAuth token.
        // If no valid token exists, request a new one.
        return new OAuthToken("token", expirationDate);
    }
};

3. Usando el Proveedor de Tokens Personalizado

Una vez que ITokenProvider está configurado, puede crear un GraphClient instancia. Este cliente usará el proveedor de token proporcionado para la autenticación al llamar a Microsoft Graph.

ITokenProvider provider = new AzureROPCTokenProvider(
        tenantId,
        clientId,
        clientSecret,
        userName,
        password,
        new String[] {"https://graph.microsoft.com/.default"}
);

IGraphClient client = GraphClient.getClient(provider, tenantId);
client.setResource(ResourceType.Users);
client.setResourceId(userName);
client.setEndpoint("https://graph.microsoft.com");

// Now you can call Microsoft Graph APIs
var folders = client.listFolders(null);
for (GraphFolderInfo folder : folders) {
    System.out.println(folder.getDisplayName());
}

Después de que el cliente sea creado y autenticado, puede comenzar a hacer solicitudes a los servicios de Microsoft Graph.