From e8974376c55d5750dba42a3e97bf62bad9ec956d Mon Sep 17 00:00:00 2001 From: Jonathan Jenne Date: Wed, 6 Sep 2023 10:24:46 +0200 Subject: [PATCH] Messaging: First working version of OAuth2 --- Messaging/Mail/MailFetcher.vb | 9 +++++-- Messaging/Mail/MailSender.vb | 4 ++-- Messaging/Mail/MailSession.vb | 44 ++++++++++++++++++++++++++++++----- Messaging/Mail/OAuth2.vb | 19 +++++++++------ 4 files changed, 59 insertions(+), 17 deletions(-) diff --git a/Messaging/Mail/MailFetcher.vb b/Messaging/Mail/MailFetcher.vb index fc07ee0b..ef161465 100644 --- a/Messaging/Mail/MailFetcher.vb +++ b/Messaging/Mail/MailFetcher.vb @@ -30,11 +30,16 @@ Namespace Mail End Sub Public Function Connect(pServer As String, pPort As Integer, pUser As String, pPassword As String, pAuthType As String) As MailSession.SessionInfo - Return MailSession.ConnectToServer(pServer, pPort, pUser, pPassword, pAuthType, New MailSession.MailSessionOptions) + Return MailSession.ConnectToServerWithBasicAuth(pServer, pPort, pUser, pPassword, pAuthType, New MailSession.MailSessionOptions) + End Function + + Public Function ConnectToO365(pUser As String, pClientId As String, pTenantId As String, pClientSecret As String) + Dim oOptions = New MailSession.MailSessionOptions With {.EnableTls1_2 = True} + Return MailSession.ConnectToServerWithO365OAuth(pUser, pClientId, pTenantId, pClientSecret, oOptions) End Function Public Function Connect(pServer As String, pPort As Integer, pUser As String, pPassword As String, pAuthType As String, pOptions As MailSession.MailSessionOptions) As MailSession.SessionInfo - Return MailSession.ConnectToServer(pServer, pPort, pUser, pPassword, pAuthType, pOptions) + Return MailSession.ConnectToServerWithBasicAuth(pServer, pPort, pUser, pPassword, pAuthType, pOptions) End Function Public Function Disconnect() As Boolean diff --git a/Messaging/Mail/MailSender.vb b/Messaging/Mail/MailSender.vb index c3bf7eb0..230438bf 100644 --- a/Messaging/Mail/MailSender.vb +++ b/Messaging/Mail/MailSender.vb @@ -20,11 +20,11 @@ Namespace Mail End Sub Public Function Connect(pServer As String, pPort As Integer, pUser As String, pPassword As String, pAuthType As String) As MailSession.SessionInfo - Return MailSession.ConnectToServer(pServer, pPort, pUser, pPassword, pAuthType, New MailSession.MailSessionOptions) + Return MailSession.ConnectToServerWithBasicAuth(pServer, pPort, pUser, pPassword, pAuthType, New MailSession.MailSessionOptions) End Function Public Function Connect(pServer As String, pPort As Integer, pUser As String, pPassword As String, pAuthType As String, pOptions As MailSession.MailSessionOptions) As MailSession.SessionInfo - Return MailSession.ConnectToServer(pServer, pPort, pUser, pPassword, pAuthType, pOptions) + Return MailSession.ConnectToServerWithBasicAuth(pServer, pPort, pUser, pPassword, pAuthType, pOptions) End Function Public Function Disconnect() As Boolean diff --git a/Messaging/Mail/MailSession.vb b/Messaging/Mail/MailSession.vb index 1ac583e5..61c30bfc 100644 --- a/Messaging/Mail/MailSession.vb +++ b/Messaging/Mail/MailSession.vb @@ -69,7 +69,7 @@ Namespace Mail ''' ''' ''' - Public Function ConnectToServer(pServer As String, pPort As Integer, pUser As String, pPassword As String, pAuthType As String, pOptions As MailSessionOptions) As SessionInfo + Public Function ConnectToServerWithBasicAuth(pServer As String, pPort As Integer, pUser As String, pPassword As String, pAuthType As String, pOptions As MailSessionOptions) As SessionInfo Dim oSession = New SessionInfo With { .Server = pServer, .Port = pPort, @@ -91,6 +91,30 @@ Namespace Mail Return ConnectToServer(oSession, pOptions) End Function + Public Function ConnectToServerWithO365OAuth(pUser As String, pClientId As String, pTenantId As String, pClientSecret As String, pOptions As MailSessionOptions) As SessionInfo + Dim oSession = New SessionInfo With { + .Server = OAuth2.O365_SERVER, + .ClientId = pClientId, + .ClientSecret = pClientSecret, + .TenantId = pTenantId, + .User = pUser, + .AuthType = AUTH_OAUTH2 + } + + Logger.Debug("Connecting to Server..") + Logger.Debug("Server: [{0}]", oSession.Server) + Logger.Debug("User: [{0}]", oSession.User) + Logger.Debug("ClientId: [{0}]", oSession.ClientId) + Logger.Debug("TenantId: [{0}]", oSession.TenantId) + Logger.Debug("AuthType: [{0}]", oSession.AuthType) + + _Session = oSession + + Logger.Debug("Initializing Connection with Auth type [{0}].", oSession.AuthType) + + Return ConnectToServer(oSession, pOptions) + End Function + Private Function ConnectToServer(pSession As SessionInfo, pOptions As MailSessionOptions) As SessionInfo AddHandler Client.ServerCertificateValidate, AddressOf Session_ServerCertificateValidate @@ -125,6 +149,8 @@ Namespace Mail Try If TypeOf Client Is Imap Then Dim oClient As Imap = Client + + Logger.Debug("Connecting with [ConnectSSL] on [{0}]", pSession.Server) oClient.ConnectSSL(pSession.Server) Else Throw New ApplicationException("Only OAuth2 for IMAP is not yet supported!") @@ -205,7 +231,7 @@ Namespace Mail If pSession.AuthType = AUTH_OAUTH2 Then ' SessionInfo.Password will be the access token that was obtained ' in the OAuth2 flow before - DoUseBestLogin_OAuth2(Client, pSession.User, pSession.Password) + DoUseBestLogin_OAuth2(Client, pSession) Else DoUseBestLogin_BasicAuth(Client, pSession.User, pSession.Password) End If @@ -245,7 +271,7 @@ Namespace Mail End Function Public Function TestLogin(pServer As String, pPort As Integer, pUser As String, pPassword As String, pAuthType As String, pOptions As MailSessionOptions) As Boolean - Dim oInfo = ConnectToServer(pServer, pPort, pUser, pPassword, pAuthType, pOptions) + Dim oInfo = ConnectToServerWithBasicAuth(pServer, pPort, pUser, pPassword, pAuthType, pOptions) If oInfo.Connected Then If DisconnectFromServer() Then Return True @@ -259,7 +285,6 @@ Namespace Mail End If End Function - Private Function SupportsSTARTTLS(pClient As ClientBase) If TypeOf pClient Is Smtp Then Return DirectCast(pClient, Smtp).SupportedExtensions.Contains(SmtpExtension.StartTLS) @@ -282,6 +307,8 @@ Namespace Mail End Sub Private Sub DoUseBestLogin_BasicAuth(pClient As ClientBase, pUserName As String, pPassword As String) + Logger.Debug("Logging in with Simple Auth") + If TypeOf pClient Is Smtp Then DirectCast(pClient, Smtp).UseBestLogin(pUserName, pPassword) ElseIf TypeOf pClient Is Imap Then @@ -291,9 +318,14 @@ Namespace Mail End If End Sub - Private Sub DoUseBestLogin_OAuth2(pClient As ClientBase, pUserName As String, pAccessToken As String) + Private Sub DoUseBestLogin_OAuth2(pClient As ClientBase, pSession As SessionInfo) + Logger.Debug("Logging in with O365 OAuth2") + If TypeOf pClient Is Imap Then - DirectCast(pClient, Imap).LoginOAUTH2(pUserName, pAccessToken) + Dim oOAuth = New OAuth2(LogConfig, pSession.TenantId, pSession.ClientId, pSession.ClientSecret) + Dim oAccessToken = oOAuth.GetAccessToken() + + DirectCast(pClient, Imap).LoginOAUTH2(pSession.User, oAccessToken) Else Logger.Error("Unknown session type: [{0}]", pClient.GetType.ToString) End If diff --git a/Messaging/Mail/OAuth2.vb b/Messaging/Mail/OAuth2.vb index 54dd58fb..46ba0361 100644 --- a/Messaging/Mail/OAuth2.vb +++ b/Messaging/Mail/OAuth2.vb @@ -1,6 +1,7 @@ Imports DigitalData.Modules.Base Imports DigitalData.Modules.Logging Imports DigitalData.Modules.Messaging.Mail.MailSession +Imports Limilabs.Client.IMAP Imports Microsoft.Identity.Client Public Class OAuth2 @@ -27,21 +28,25 @@ Public Class OAuth2 ClientSecret = pClientSecret End Sub - Private Async Function GetAccessToken(pSession As SessionInfo) As Task(Of String) + Public Function GetAccessToken() As String + Logger.Debug("Fetching Access Token..") + Try ' Create the application, which is defined in ' Microsoft.Identity.Client Dim oApp = ConfidentialClientApplicationBuilder. - Create(pSession.ClientId). - WithTenantId(pSession.TenantId). - WithClientSecret(pSession.ClientSecret). - Build() + Create(ClientId). + WithTenantId(TenantId). + WithClientSecret(ClientSecret). + Build() ' Request an access token Dim oScopes = New List(Of String) From {O365_SCOPE} - Dim oResult = Await oApp. + Dim oResult = oApp. AcquireTokenForClient(oScopes). - ExecuteAsync() + ExecuteAsync().Result + + Logger.Debug("Access Token fetched.") Return oResult.AccessToken Catch ex As Exception