Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  • Diese Schritte erfolgen in PowerShell, mit einem eigens zu installierenden PowerShell-Applet namens "ExchangeOnlineManagement"
  • Hiermit wird das Recht vergeben, dass man mit dem clientsecret Zugriff auf die targetMailbox hat.

Testen mit Powershell

Die Angaben in spitzen Klammern (<...>) müssen durch die ermittelten/relevanten Werte ersetzt werden.

Applet Get-IMAPAccessToken.ps1

Code Block
languagepowershell
Get-IMAPAccessToken.ps1 -tenantID "<tenantID>" -clientId "<clientID>"   -clientsecret "<clientsecret>"  -targetMailbox "<targetmailbox>" -verbose

Testscript

...

languagepowershell
collapsetrue

...


Anchor
MSAL.PS
MSAL.PS
MSAL.PS - Powershell-Wrapper für die MSAL.NET

Die Powershell-App MSAL.PS ist ein Wrapper für MSAL.NET, der es ermöglicht, die Befehle aus Powershell zu rufen.

Diese App wird nicht von Microsoft gepflegt, sie ist ein Gitub-Projekt: https://github.com/

...

AzureAD/MSAL.PS/tree/master/src

Installation von MSAL.PS

1. Powershell als Administator aufrufen

Image Added

2. Installationsbefehl eingeben

Install-Module -Name MSAL.PS

Image Added


Testen mit Powershell

Die Angaben in spitzen Klammern (<...>) müssen durch die ermittelten/relevanten Werte ersetzt werden.

Mit Get-IMAPAccessToken.PS1

1. Sicherstellen, dass der Powershell-wrapper MSAL.PS  auf dem PC installiert ist (siehe vorheriges Kapitel)

2. Die Datei Get-IMAPAccessToken.ps1 in einem beliebigen Verzeichnis ablegen (z.B. in C:\TEMP)

3. Die Werte ermitteln für

  • tenantID
  • clientID
  • clientsecret
  • targetmailbox

4. Powershell öffnen und das Skript aufrufen - dabei natürlich die <..>-Variablen durch die richtigen Werte ersetzen

Code Block
languagec#
titleAufruf für Get-IMAPAccessToken.ps1
cd \
cd Temp
.\Get-IMAPAccessToken.ps1 -tenantID "<tenantID>" -clientId "<clientID>"   -clientsecret "<clientsecret>"  -targetMailbox "<targetMailbox>" -Verbose
#>

[CmdletBinding()]
param (
    [Parameter(Mandatory = $true)][string]$tenantID,
    [Parameter(Mandatory = $true)][String]$clientId,
    
    [Parameter(Mandatory = $true,ParameterSetName="authorizationcode")][String]$redirectUri,
    [Parameter(Mandatory = $true,ParameterSetName="authorizationcode")][String]$LoginHint,
    [Parameter(Mandatory = $false,ParameterSetName="authorizationcode")][String]$SharedMailbox,

    [Parameter(Mandatory = $true,ParameterSetName="clientcredentialsSecret")][String]$clientsecret,
    [Parameter(Mandatory = $true,ParameterSetName="clientcredentialsCertificate")][String]$clientcertificate,

    [Parameter(Mandatory = $true,ParameterSetName="clientcredentialsSecret")]
    [Parameter(Mandatory = $true,ParameterSetName="clientcredentialsCertificate")]
    [String]$targetMailbox
)

function Test-IMAPXOAuth2Connectivity {
# get Accesstoken via user authentication and store Access+Refreshtoken for next attempts
if ( $redirectUri ){
    $MsftPowerShellClient = New-MsalClientApplication -ClientId $clientID -TenantId $tenantID -RedirectUri $redirectURI  | Enable-MsalTokenCacheOnDisk -PassThru
    try {
        $authResult = $MsftPowerShellClient | Get-MsalToken -LoginHint $LoginHint -Scopes 'https://outlook.office365.com/.default'
    }
    catch  {
        Write-Host "Ran into an exception while getting accesstoken user grant flow" -ForegroundColor Red
        $_.Exception.Message
        $_.FullyQualifiedErrorId
        break
    }
}

if ( $clientsecret ){
    $SecuredclientSecret = ConvertTo-SecureString $clientsecret -AsPlainText -Force
    $MsftPowerShellClient = New-MsalClientApplication -ClientId $clientID -TenantId $tenantID -ClientSecret $SecuredclientSecret 
    try {
        $authResult = $MsftPowerShellClient | Get-MsalToken -Scopes 'https://outlook.office365.com/.default'
    }
    catch  {
        Write-Host "Ran into an exception while getting accesstoken using clientsecret" -ForegroundColor Red
        $_.Exception.Message
        $_.FullyQualifiedErrorId
        break
    }
}


if ( $clientcertificate ){
    $ClientCert = Get-ChildItem "cert:\currentuser\my\$clientcertificate"
    $MsftPowerShellClient = New-MsalClientApplication -ClientId $clientID -TenantId $tenantID -ClientCertificate $ClientCert
    try {
        $authResult = $MsftPowerShellClient | Get-MsalToken -Scopes 'https://outlook.office365.com/.default'
    }
    catch  {
        Write-Host "Ran into an exception while getting accesstoken using certificate" -ForegroundColor Red
        $_.Exception.Message
        $_.FullyQualifiedErrorId
        break
    }
}



$accessToken = $authResult.AccessToken
Write-Verbose "Access Token -- $accessToken"
$userName = $authResult.Account.Username

# build authentication string with accesstoken and username like documented here
# https://docs.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth#authenticate-connection-requests

# in the case of client credential usage we need to add the target mailbox like shared mailbox access to the SASL string
if ( $targetMailbox) { $SharedMailbox = $targetMailbox }

if ( $SharedMailbox ) {
    $b="user=" + $SharedMailbox + "$([char]0x01)auth=Bearer " + $accessToken + "$([char]0x01)$([char]0x01)"
    Write-Host "Accessing Sharedmailbox - $SharedMailbox - with Accesstoken of User $userName." -ForegroundColor DarkGreen
} else {
        $b="user=" + $userName + "$([char]0x01)auth=Bearer " + $accessToken + "$([char]0x01)$([char]0x01)"
        }

$Bytes = [System.Text.Encoding]::ASCII.GetBytes($b)
$POPIMAPLogin =[Convert]::ToBase64String($Bytes)

Write-Verbose "SASL XOAUTH2 login string $POPIMAPLogin"

# connecting to Office 365 IMAP Service
Write-Host "Connect to Office 365 IMAP Service." -ForegroundColor DarkGreen
$ComputerName = 'Outlook.office365.com'
##$Port = '993'
$Port = '995'
    try {
        $TCPConnection = New-Object System.Net.Sockets.Tcpclient($($ComputerName), $Port)
        $TCPStream = $TCPConnection.GetStream()
        try {
            $SSLStream  = New-Object System.Net.Security.SslStream($TCPStream)
            $SSLStream.ReadTimeout = 5000
            $SSLStream.WriteTimeout = 5000     
            $CheckCertRevocationStatus = $true
            $SSLStream.AuthenticateAsClient($ComputerName,$null,[System.Security.Authentication.SslProtocols]::Tls12,$CheckCertRevocationStatus)
        }
        catch  {
            Write-Host "Ran into an exception while negotating SSL connection. Exiting." -ForegroundColor Red
            $_.Exception.Message
            break
        }
    }
    catch  {
    Write-Host "Ran into an exception while opening TCP connection. Exiting." -ForegroundColor Red
    $_.Exception.Message
    break
    }    

    # continue if connection was successfully established
    $SSLstreamReader = new-object System.IO.StreamReader($sslStream)
    $SSLstreamWriter = new-object System.IO.StreamWriter($sslStream)
    $SSLstreamWriter.AutoFlush = $true
    $SSLstreamReader.ReadLine()

    Write-Host "Authenticate using XOAuth2." -ForegroundColor DarkGreen
    # authenticate and check for results
 ##   $command = "A01 AUTHENTICATE XOAUTH2 {0}" -f $POPIMAPLogin
    $command = "AUTH = XOAUTH2"
    Write-Verbose "Executing command -- $command"
    $SSLstreamWriter.WriteLine($command)
   
    ## begin 
    $command = $POPIMAPLogin
    $SSLstreamWriter.WriteLine($command) 
    ## end
    #respose might take longer sometimes
    while (!$ResponseStr ) { 
        try { $ResponseStr = $SSLstreamReader.ReadLine() } catch { }
    }

    if ( $ResponseStr -like "*OK AUTHENTICATE completed.") 
    {
        $ResponseStr
        Write-Host "Getting mailbox folder list as authentication was successfull." -ForegroundColor DarkGreen
        $command = 'A01 LIST "" *'
        Write-Verbose "Executing command -- $command"
        $SSLstreamWriter.WriteLine($command) 

        $done = $false
        $str = $null
        while (!$done ) {
            $str = $SSLstreamReader.ReadLine()
            if ($str -like "* OK LIST completed.") { $str ; $done = $true } 
            elseif ($str -like "* BAD User is authenticated but not connected.") { $str; "Causing Error: IMAP protcol access to mailbox is disabled or permission not granted for client credential flow. Please enable IMAP protcol access or grant fullaccess to service principal."; $done = $true} 
            else { $str }
        }

        Write-Host "Logout and cleanup sessions." -ForegroundColor DarkGreen
        $command = 'A01 Logout'
        Write-Verbose "Executing command -- $command"
        $SSLstreamWriter.WriteLine($command) 
        $SSLstreamReader.ReadLine()

    } else {
        Write-host "ERROR during authentication $ResponseStr" -Foregroundcolor Red
    }

    # Session cleanup
    if ($SSLStream) {
        $SSLStream.Dispose()
    }
    if ($TCPStream) {
        $TCPStream.Dispose()
    }
    if ($TCPConnection) {
        $TCPConnection.Dispose()
    }
}

#check for needed msal.ps module
if ( !(Get-Module msal.ps -ListAvailable) ) { Write-Host "MSAL.PS module not installed, please check it out here https://www.powershellgallery.com/packages/MSAL.PS/" -ForegroundColor Red; break}

# execute function
Test-IMAPXOAuth2Connectivity<targetmailbox>" -verbose

Ergebnis:

Image Added

2024-12-12/rsc - hier gibt es noch einen Fehler