-
Notifications
You must be signed in to change notification settings - Fork 0
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
Research: OATH2 support for accessing O365 mailboxes via IMAP #313
Comments
Unfortunately, I no longer have access to an IMAP-enabled O365 account for testing, so this might be more challenging than in the past. |
Adam, I'll be happy to test the code against the Libraries' email accounts. |
This one seems very promising. A quick scan of recent changes suggests that it may be worth splitting off O365 functionality into a separate plugin. Will require further review to be sure. |
Worked on this some yesterday as part of assisting with a Redmine installation. Based on the yesterday's work, it looks like supporting the Longer term, support for "daemon applications" appears to be what is needed:
On a different note, while assisting with the Redmine installation I can see the need for a small tool that performs the following functions:
This would allow existing Redmine installations to pretty much work as-is, assuming that the sysadmins of those instances already use a wrapper script of some kind to drive the process. The scope of such a tool may warrant a separate project. The reason it may fit here is that the logic used to drive the tool could be used by a Nagios plugin (either the existing one or a new one) and the |
Continuing with the "thinking out loud" bit, a small workaround tool could be produced that emits a properly encoded (xoauth2) token. This encoded token could be used in place of the original password in the A minor enhancement to the Longer term the |
The |
Based on these sources: XOAUTH2 is considered a legacy authentication mechanism and is superseded by OAUTHBEARER. Per about 30 minutes ago, outlook.office365.com indicates these capabilities:
Unfortunately, OAUTHBEARER is not included among them, so isn't an option for us. Since the auth mechanism is officially dropped, we'll have to bundle the functionality locally. The first one is surprising. Haven't tested yet to see whether it actually works as advertised. |
After some trial & error I've prototyped the process for retrieving a token using the client credentials auth flow and it appears to be working reliably. One "gotcha" encountered was the scopes. With these scopes set the process worked:
The last one has to be granted by a tenant administrator. Per https://blog.rebex.net/office365-ews-oauth-unattended:
Other sources have said the same thing: Delegated scopes are not needed for the The service principal also had to be granted access to a list of applicable mailboxes that we wished to access using the registered application. From the application, I had to request a token with the scope of In short, there are multiple "must have" items for this to work properly. Failing to meet any of the requirements results in failure to access the intended mailboxes. |
I'm planning to build a separate plugin specific to O365 IMAP access, at least until the dust settles and the design is clear. For the
This wasn't bad at all; this is probably why the library authors assumed it would be a small lift for library consumers to bundle the functionality directly. Perhaps in the future XOAUTH2 support could be returned to the upstream library if enough developers express an interest. |
On a related note, one of our O365 administrators provided a copy of the https://github.com/DanijelkMSFT/ThisandThat/blob/main/Get-IMAPAccessToken.ps1 script (commit Based on prior experience and research, it appeared that IPv6 was to blame. In the end, the fix is to explicitly enable CRLF line termination for the IMAP commands issued instead of letting PowerShell guess which should be used. Pull Request submitted to fix the script for others using the script on non-Windows systems. |
Learned that the Ruby IMAP From # Sends an AUTHENTICATE command to authenticate the client.
# The +auth_type+ parameter is a string that represents
# the authentication mechanism to be used. Currently Net::IMAP
# supports the authentication mechanisms:
#
# LOGIN:: login using cleartext user and password.
# CRAM-MD5:: login with cleartext user and encrypted password
# (see [RFC-2195] for a full description). This
# mechanism requires that the server have the user's
# password stored in clear-text password.
#
# For both of these mechanisms, there should be two +args+: username
# and (cleartext) password. A server may not support one or the other
# of these mechanisms; check #capability() for a capability of
# the form "AUTH=LOGIN" or "AUTH=CRAM-MD5".
#
# Authentication is done using the appropriate authenticator object:
# see @@authenticators for more information on plugging in your own
# authenticator.
#
# For example:
#
# imap.authenticate('LOGIN', user, password)
#
# A Net::IMAP::NoResponseError is raised if authentication fails.
def authenticate(auth_type, *args)
auth_type = auth_type.upcase
unless @@authenticators.has_key?(auth_type)
raise ArgumentError,
format('unknown auth type - "%s"', auth_type)
end
authenticator = @@authenticators[auth_type].new(*args)
send_command("AUTHENTICATE", auth_type) do |resp|
if resp.instance_of?(ContinuationRequest)
data = authenticator.process(resp.data.text.unpack("m")[0])
s = [data].pack("m0")
send_string_data(s)
put_string(CRLF)
end
end
end This means that the custom authentication mechanism does not need to handle base64 encoding on its own. It just needs to handle formatting the provided username/password (or in the case of XOAUTH2 the username/unencoded token) and passing it back (where it is then base64 encoded). refs: |
For reference, here is a curl command used to fetch a token: curl https://login.microsoftonline.com/TENAT_ID_HERE/oauth2/v2.0/token -X POST -H "Content-type: application/x-www-form-urlencoded" -d "client_id=CLIENT_ID_HERE&scope=https%3A%2F%2Foutlook.office365.com%2F.default&grant_type=client_credentials&username=me@example.com&client_secret=CLIENT_SECRET_HERE" and the "pretty printed" JSON response: {
"token_type": "Bearer",
"expires_in": 3599,
"ext_expires_in": 3599,
"access_token": "TOKEN_HERE"
} Note that a refresh token isn't specified. Perhaps this isn't available for this specific grant type? |
Per RFC6749, Section 4.4.3:
refs: |
Of note:
The necessary OAuth2 flow was added in June 30 of this year. From the time I filed this GH issue the needed support was added only 4 months prior. refs: |
- rename existing monitoring plugin to make explicitly clear that it supports Basic Auth only - add new monitoring plugin to support the Client Credentials OAuth2 flow - add xoauth2 prototype tool to convert given username and token to XOAuth2 formatted string (optionally encoded to support SASL XOAUTH) - update `list-emails` tool to support either of Basic Auth or Client Credentials OAuth2 flow depending on which config file settings are used - refresh README to provide coverage for new settings/plugin and liberal collection of ref links for context - refresh `list-emails` config file example coverage - update existing file to make clear that it is intended for Basic Auth - add new file to cover settings for Client Credentials OAuth2 flow refs GH-313
Considering GH-335 to be the culmination of the research/prototyping work noted on this and related GH issues. |
Overview
I was reminded today of the impending retirement of basic authentication for O365. From what I've read IMAP support isn't going away, you'll just now need to provide a token in place of username/password pair as is, for a time, still supported.
I've not researched yet what it will take to work with OAuth2 tokens.
Very light scanning of a Redmine issue on the topic provided multiple CLI examples (via curl) for fetching a token and then using that token to access a mailbox. An equivalent implementation might be sufficient for our needs.
References
General:
Redmine:
OAuth 2.0 Resource Owner Password Credentials (ROPC) grant:
Some Go-specific references:
XOAuth2String
function truncates result sqs/go-xoauth2#1RFCS:
Other projects:
The text was updated successfully, but these errors were encountered: