-
Notifications
You must be signed in to change notification settings - Fork 142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for XOAUTH2 SASL authentication #192
Comments
Hi, |
Remy, Now that Microsoft has removed all but OAuth2 authentication for IMAP, this is now on our front burner. Any resolution in sight? |
I do have some new |
I have now pushed a new |
Thanks Remy, The above sample by geoffsmith82 works. Confusing for me, but I've been able to implement it into our app. Now debugging. Just wanted to say thanks. For anyone that needs help, the following Google link pointed me in the right direction: |
OK, but do things also work when using the new SASL classes I checked in, rather than using geoff's SASL classes? |
Thank you Remy. I gave it a fair shot yesterday, but had compile issues. Differences in procedure calls, declaration of uses in implementation when it belonged in interface (IdGlobals for example), etc. I would have preferred a subclass for now vs the implementation in the base classes and this is where geoffsmith82's implementation works. Sorry, I can not say if it works or not. I may give it another shot soon. Thanks again, really. |
Can you elaborate on the errors?
FYI, package files for Alexandria (280) have now been checked in.
What do you mean? The new SASL classes are subclasses. |
Hi Remy What do you recommend? Have a missed the token generator in your code? function TIdSASLOAuth2Base.TryStartAuthenticate(const AHost: string; const APort: TIdPort; const AProtocolName : string; var VInitialResponse: String): Boolean; |
Correct, it does not. The user is responsible for obtaining the necessary token first, such as via HTTP to whatever OAuth provider they are working with (Google, Microsoft, etc), and then assign the token to the SASL component.
No. Outside of submitting the OAuth token over SASL, I do not have any other OAuth code implemented at this time. |
Thanks Remy, IIm getting my own tokens now and passing them in with OnGetAccessToken. Geoffs class above was useful to get started but didn't cover the OAuth requirements i had. |
Hi Thanks for this. I have downloaded Remy's branch, and can see the IdSASLOAuth.pas unit installed. However there is no component installed for TIdSASLOAuth2Base component in my component suite. (I completely uninstalled Indy from Delphi and deleted all references before installing this so I'm fairly sureI have the latest install). It this not an actual design time component? Can you please advise if I need to try and use this another way? And are you able to confirm please if you actually were able to get POP3 working with Microsoft oAuth? Thanks Adam |
I hadn't yet updated the FYI,
It is now.
You can alternatively create the components in code at runtime, like any other component.
At this time, I haven't tested any of this new code myself. |
Thanks Remy, I've updated to the latest branch and indeed have access to the 3 new components. I have added these to a test project and added them to the POP3 SASLMechanisms, but when testing POP3 on Office365 still get the error "Doesn't support AUTH or the specified SASL handlers". I'm assuming there's still work to be done before Indy is compatible with Microsoft's changes? |
"I've updated to the latest branch and indeed have access to the 3 new components. I have added these to a test project and added them to the POP3 SASLMechanisms, but when testing POP3 on Office365 still get the error "Doesn't support AUTH or the specified SASL handlers"." I have it working for MS IMAP and POP. If you see above I had to write a class to get an OAuth token from the MS service then pass it into the Indy component which uses that token to authorize the IMAP or POP connection. Works for google too but you need a class that can get a token from the google service (similar but just different parameters passed in) |
That error message means that the POP3 server's
Microsoft uses the Unfortunately, Microsoft's SASL documentation only demonstrates IMAP querying the server for OAuth2 support via a |
Thanks for your replies LongDelphiHalfLife and Remy I must be doing something wrong as I'm trying to follow what LongDelphiHalfLife has done, but the TidSASLXOAuth2's OnGetAccessToken event never fires. I get a "Doesn't support AUTH or the specified SASL Handlers!!" error raised when I perform the POP3's Connect command. I've double check I have assigned the TidSASLXOAuth2 component to the SASLMechanisms (moved it from Available to Assigned) so I'm at a loss why it's not executing the onGetToken event or why it doesn't believe that the component isn't supported. It's very encouraging to hear that LDHL has this actually working with Microsoft for POP3 - gives me hope that there's a solution with Indy that I may be able to implement before the Microsoft deadline - I just don't know why it's failing for me. |
As I explained in my previous reply, that error means that When logging in to a server, Please check this for yourself. You can either:
The
Are you seeing that entry when logging in to your Microsoft server?
What does that mean?
Because it is not attempting to login with XOAuth2.
Because it thinks Microsoft doesn't support XOAuth2.
I haven't looked at LDHL's implementation, but I suspect it is simply ignoring the |
Good Morning Remy, Thanks for your reply (and your patience!). I'm not fully familiar with CAPA/XOAuth2 protocols and am undergoing a steep learning curve with this one. I really appreciate your assistance! I think I understand a lot more now.
Sorry - what I mean by this is when I click on the idPop3 component in the designer, and open up SASLMechanism my idSASLXOauth2 component is in the Available list (left hand side). I move this to the Assigned side to confirm that it's actually being assigned to the POP3 component.
Thanks very much for the details. Unfortunately no - I'm not seeing that when connecting to the MS Server. What I have in my debug log is as follows:
...and then I get the Doesn't support AUTH or specified SASL handlers. So it looks like the response is definitely missing the XOAUTH2 that Indy is expecting. I have checked out the Capabilities property after calling connect as you suggested. I get TOP, UIDL and STLS only. I thought I'd try and be sneaky and do a force, so I went and added:
but then in the logs I get:
I'm guessing from this it seems that my approach of manually adding a capability that wasn't returned was successful to force XOAuth2- but then I get the protocol error occurs immediately after that as Microsoft rejects my S:AUTH XOAUTH2 request. |
Oh, OK. I wasn't aware that there was a custom design-time Form being used to edit the
Well, then that is why you are getting the error raised.
Interesting, I would have expected
Odd, considering that is following Microsoft's example of sending Well, try the latest branch (you can remove your hack), and see if the same error still occurs. |
Thanks Remy. You are correct! I've updated and tried that and on the 2nd CAPA request it shows up properly, but it is still unsuccessful. I think I've found the problem! (Just not sure how to fix it). I manually tried logging in with OpenSSL typing in the commands myself. If I try and replicate what Indy is doing I get the same error. If on the other hand I execute AUTH XOAUTH2 as a command, wait for a response, and then paste in the token and send that through as a separate command - it executes successfully. I notice in IdSASLCollection on line 235 - this is where the problem occurs:
Indy is sending through ...
... as a single transmission and Microsoft doesn't appear to like it. However it would appear if AUTH XOAUTH2 is sent through, wait for a response and then the Token is sent through after - Microsoft is happy. I'm not sure if it's of any help, but I've come up with the following code to create things at runtime (to try and make it easier for discussion and to see what I'm actually doing instead of having components on a form at design time):
I hope this is of some help. |
Hi, I can confirm that POP3, IMAP4, SMTP with MS OAUTH2 and Indy (sasl-oauth branch from about month ago, Delphi 10.4) works correctly.
For POP3 connection I had to fix AUTH XOAUTH2 with token in new line (because I got "Protocol error" respone).
I'm not sure it this is required for other OAUTH2 providers. |
Thanks so much for your confirmation and code snippet. I have now changed line 235 in IdSASLCollection.pas from:
to:
... and can confirm that I am successfully authenticating with Microsoft 365! Again - thank you!!! |
@KrystianBigaj I wouldn't make the change in PerformSASLLogin as the the 2 line login for Microsoft isn't used by everyone (specifically Google). I would add an property to the SASL class for a Two line POP authentication. |
Most POP3 providers support the version of the THIS IS BY DESIGN. You should NOT have had to make ANY code changes to If you really want to disable the 1st 1-line I have now added a As for |
Hi Remy, Thanks for your reply, and thanks for adding in SASLCanAttemptInitialResponse. Just to clarify...
I'm confused by this. With the example code shown above on how I connect - I was definitely getting errors with Microsoft until I made code changes Krystian mentioned to the code - however if I understand you correctly - I shoudn't have needed to make that change because the retry logic was implemented in PerformSASL(). So now I'm confused as to why it is failing for me with Microsoft as it certainly didn't seem to be retrying using the second method after failure of the first. I will revert changes and give SASLCanAttemptInitialResponse a go- but I'm still curious to know that what I'm experiencing (failure to authenticate) does not match up with what your saying (retry logic was implemented and there should be no need to make any changes to the code) - that I shouldn't need SASLCanAttemptInitialResponse at all? |
Remy @rlebeau |
@KrystianBigaj , @hairy77 TIA |
@marcin-bury depends on what type of library (SMTP, Pop3, IMAP) you use in your Delphi-project. In my case i've used the TIdSMTP-component with the following scope; "https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send offline_access". Used endpoints are https://login.microsoftonline.com/common/oauth2/v2.0/authorize and https://login.microsoftonline.com/common/oauth2/v2.0/token |
@joostcrommert1 thanks for the response. TIA |
@marcin-bury I haven't used IMAP myself, but I guess the set-up would be the same as POP3; Providers[ProviderInfo] is based on the example that @geoffsmith82 posted earlier in this thread.
GetAccessCode:
|
Have you tried using the
Why are you using the
Also, what is the |
@rlebeau |
Btw, @joostcrommert1 , thanks for sharing |
Sorry guys for non english post |
@rlebeau code is messy indeed, was happy with a working example so didn't bother to clean up the code. |
@joostcrommert1 |
This looks wrong to me, since the Graph API is not being accessed. See: Authenticate an IMAP, POP or SMTP connection using OAuth |
Hello.
I've got a socket error 10038, or a timeout error |
Did you verify you are actually receiving a token?
You really shouldn't be using the
On a side note: you are not assigning an Owner to these objects, so they are going to be leaked unless you Free them manually when you are done using them.
You don't need that.
You can assign the
Are you getting any events?
On which line of code, exactly? Did the |
Thanks for your quick reply. Yes, i've a token, and today i've an event (some moment i've nothing else error 10038) Here the events : I've added [SRV] & [PGM] before each line to understand the log
|
If I can remember correctly when I got this error it was because the line |
Thanks for your answer.
|
That line I posted looked like it was. You would need to run it through a base64 decoder though to see if your email address is at the start. |
Thanks ! |
Have a look at the bottom of my project page for what you need to configure in Microsoft's options. |
Edit : it work's with an other java program :-/ so the pbm is in my Delphi code |
Yes, it does use base64. The For instance, in your log message |
I wanted to try XOAUTH2 on C++ Builder (11.3). I cloned the project, built the sasl-oauth branch, and was I able to build and link my own project after updating the Indy. Now I'm having difficulties installing the component to design time palette as I don't have Delphi.Personality available and on the other hand, the header file (hpp) for this SASL is not generated by the build job. Should it be possible to use this with C++ Builder as it is at the moment? |
The |
Thank you! I was able to add the new SASL mechanism and building the C++ application with this update. However, I haven't been able to test it end to end yet, as I'm having difficulties getting the Azure app registrations in place and getting valid token for the bearer. I'm hitting "535 5.7.3 Authentication unsuccessful" with curl as well, so I need to sort that out next. |
Check out the documentation here. SMTP can be disabled on the Organisation and/or the user |
Any progress on it? |
Nothing new lately. I recently installed RAD Studio 12, so I should be able to work more on it this year. |
Outlook/Hotmail/Live, Gmail, and possibly others, support XOAUTH2 authentication over SASL for POP3, SMTP and IMAP. Indy should implement a TIdSASL component to support this. This way, users do not need to create application-specific passwords when 2-step verification is enabled in their accounts.
https://developers.google.com/gmail/imap/xoauth2-protocol
https://msdn.microsoft.com/en-us/library/dn440163.aspx
The text was updated successfully, but these errors were encountered: