Проверка подлинности Microsoft Outlook oAuth2.0

У нас есть демон-приложение, которое устанавливает IMAP-соединение для доступа к почтовому ящику пользователя. Ранее мы использовали простой метод аутентификации с использованием идентификатора электронной почты и пароля для установления соединения IMAP. Теперь, когда Microsoft заблокировала процесс аутентификации этого типа и представила oAuth2.0.

Мой вопрос здесь. Мне удалось установить IMAP-соединение с пользователем, который находится внутри моего арендатора. Но я не могу понять, как это можно сделать, если мне нужно получить доступ к почтовому ящику пользователя, который не входит в мой клиент, или мне нужно получить доступ к почтовому ящику любой личной учетной записи Outlook.

1 ответ

Я попытался воспроизвести то же самое в своей среде и получил следующие результаты:

Обратите внимание , что если вы хотите получить доступ к почтовому ящику пользователя, который не относится к вашему арендатору, или вам необходимо получить доступ к почтовому ящику любой личной учетной записи Outlook, вам необходимо зарегистрировать Multi-Tenant Azure AD Applicationкак показано ниже:

введите описание изображения здесь

Я создал мультитенантное приложение Azure AD и предоставил разрешения API :

введите описание изображения здесь

Теперь я зарегистрировал субъектов-служб в Exchange с помощью следующих команд:**

      Connect-ExchangeOnline -Organization TenantID

New-ServicePrincipal -AppId AppID -ServiceId ObjectID [-Organization OrganizationID]
Get-ServicePrincipal | fl

введите описание изображения здесь

Я предоставил субъекту-службе доступ к одному почтовому ящику :

      Add-MailboxPermission -Identity "USER@XXX.com" -User 
ServicePrincipal_ID> -AccessRights FullAccess

Test-ApplicationAccessPolicy -Identity "USER@XXX.com" -AppId AppID

введите описание изображения здесь

Я сгенерировал токен доступа через Postman для многопользовательского приложения , используя следующие параметры:

      https://login.microsoftonline.com/common/oauth2/v2.0/token

client_id:5f3068f5-a920-4d6d-9742-XXXXXX
client_secret:ESJ8Q~ShJVdlY2MhKicyTEApGdtZh*******
scope:https://outlook.office365.com/.default
grant_type:client_credentials

введите описание изображения здесь

Чтобы сделать то же самое в JAVA, вы можете сослаться на приведенный ниже пример кода пользователем3206771 в этой теме SO :

      public String getAccessTokenByClientCredentialGrant()  {       
    String accessToken = null;
    String clientId = "CLIENTID";
    String secret = "CLIENTSECRET";
    String authority = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
    String scope = "https://outlook.office365.com/.default";
    log.info("Client ID : "+clientId);
    log.info("Client Secret : "+secret);
    log.info("Auth Server: "+authority);
    log.info("Scope: "+scope);
        try {
              ConfidentialClientApplication app = ConfidentialClientApplication.builder(
                clientId,
              ClientCredentialFactory.createFromSecret(secret))
                .authority(authority)
                .build();   
  
        ClientCredentialParameters clientCredentialParam = ClientCredentialParameters.builder(
                Collections.singleton(scope))
                .build();
        
        CompletableFuture<IAuthenticationResult> future = app.acquireToken(clientCredentialParam);
        IAuthenticationResult result = future.get();
        accessToken = result.accessToken();
        
    } catch(Exception e) {
        log.error("Exception in acquiring token: "+e.getMessage());
        e.printStackTrace();
    }
    log.info("Access Token : "+accessToken);
    return accessToken;
}
public Store connect(String userEmailId, String oauth2AccessToken) throws Exception {
    String host = "outlook.office365.com";
    String port = "993";
    Store store = null;
     
    String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
    Properties props= new Properties();
    props.put("mail.imaps.ssl.enable", "true");
    props.put("mail.imaps.sasl.enable", "true");
    props.put("mail.imaps.port", port);
    props.put("mail.imaps.auth.mechanisms", "XOAUTH2");
    props.put("mail.imaps.sasl.mechanisms", "XOAUTH2");
    props.put("mail.imaps.auth.login.disable", "true");
    props.put("mail.imaps.auth.plain.disable", "true");
    props.setProperty("mail.imaps.socketFactory.class", SSL_FACTORY);
    props.setProperty("mail.imaps.socketFactory.fallback", "false");
    props.setProperty("mail.imaps.socketFactory.port", port);
    props.setProperty("mail.imaps.starttls.enable", "true");
    props.put("mail.debug", "true");
    props.put("mail.debug.auth", "true");
    Session session = Session.getInstance(props);
    session.setDebug(true);
    store = session.getStore("imaps");
    log.info("OAUTH2 IMAP trying to connect with system properties to Host:" + host + ", Port: "+ port
            + ", userEmailId: " + userEmailId+ ", AccessToken: " + oauth2AccessToken);
    try {
    
        store.connect(host, userEmailId, oauth2AccessToken);
        log.info("IMAP connected with system properties to Host:" + host + ", Port: "+ port
            + ", userEmailId: " + userEmailId+ ", AccessToken: " + oauth2AccessToken);
        if(store.isConnected()){
            log.info("Connection Established using imap protocol successfully !");      
        }
    } catch (Exception e) {
        log.error("Store.Connect failed with the errror: "+e.getMessage());
        StringWriter sw = new StringWriter();
        e.printStackTrace(new PrintWriter(sw));
        String exceptionAsString = sw.toString();
        log.error(exceptionAsString);
     
    }
    return store;
}
public void getEmailContents() throws Exception {
    Store store = null;
       String accessToken = getAccessTokenByClientCredentialGrant();
    String emailId = "<email which needs to be read>";
    try {
        store = connect(emailId, accessToken );
    } catch (Exception ex) {
        log.error("Exception in connecting to email " + ex.getMessage());
        ex.printStackTrace();
        }
   }
Другие вопросы по тегам