tarickb / sasl-xoauth2

SASL plugin for XOAUTH2
Other
72 stars 20 forks source link

Initial Token Generation 401 unauthorized #70

Open JjfBcn opened 1 year ago

JjfBcn commented 1 year ago

Hi,

Thank you for your extraordinary work!

We're having some troubles configuring the initial token generation, it would be appreciated some light over obscurity!

We're always receving "HTTP Error 401: Unauthorized"

$ sasl-xoauth2-tool get-token --client-id=9062----xxxxxxxx --tenant=2a2as*---**-***** outlook /etc/tokens/prova.test@domain.com Please visit the following link in a web browser, then paste the resulting URL:

https://login.microsoftonline.com/2a2ac957-8eaf-4083-bfc2-3164d10a3c2f/oauth2/v2.0/authorize?client_id=9062****-****-****-****-xxxxxxxx&response_type=code&redirect_uri=https%3A%2F%2Flogin.microsoftonline.com%2Fcommon%2Foauth2%2Fnativeclient&response_mode=query&scope=openid+offline_access+https%3A%2F%2Foutlook.office.com%2FSMTP.Send

Resulting URL: https://login.microsoftonline.com/common/oauth2/nativeclient?code=0.AR8AV8kqKq-Og0C_wjFk0Qo8LzXlYpCb-hBDqB4wY988QfmFAAA.AgABAAIAAAD--DLA3VO7QrddgJg7WevrAgDs_wUA9P_KJUA-asdfasdfasdfZ-Km5Q2pnRothbq32HN_asdfasdfaASDFASDf3xfoCzlKpjn1CfQflh5ATiX8upNBXop2uZKUguFs046fFCxgWLMPPs5poRME8OSe0mBqGhKsc2zU1DyPxX5NpAXyKTtgz4Ei3-fD_88asdfasdfasd_RVffnve9aeOTTDZiyKC9mytAnCJ5VzxzvIFOGdisya5-PSK_X2DMyqZkFgUMBokCKXoeDK5qiBuBGI_alre7DJWqgnrIcafdTZGSHW5h9x96a3lpkUCWDZmsliOe6wyCOygrRjNXd3doL0UpEknZ-4_DZMEFMmLVWnCNSmkHTNp0x4U6pXyKswDDuWde94D_asdfasdfASDfasdfaSDfasdjvaUbg3HaxyRJnYaG48xBBsPHzD8A0eo3qHeEPXyB2K7etlmpVtA69FC6Jasdfa-TAafdajopasdcasFoZrUoBHlVPbnZoBd_jwKDJLRz2KnZqPKqegTcZZ4_IgsE99NQZ2w3aIUBeUs34yqDTfLYzU0MJP78UStQ4eSpDNPcaqSPwKZb5lL51Pj0qoj7IihDLLWgSiapTazfy0zCcWp-ZF3R0e1qOufXpFkZfOyy8zpx6b5qL4L8ElICYFLkMTTviMRMmfhF4n4vbkEgeIyfYSQhW9NlNoBuRnByPC6nEC0uQjI-kQz0KuYMIRvc5tDc9wN_1XM0bjWCXqtES7J6T41F68lLIOqdVPbQV02S3C43nYj5vfrf0VdYmY0xSp3rYdovM&session_state=43535436-6104-4f39-8a43-rcdf2a8b888 Traceback (most recent call last): File "/usr/bin/sasl-xoauth2-tool", line 301, in main() File "/usr/bin/sasl-xoauth2-tool", line 294, in main args.func(args) File "/usr/bin/sasl-xoauth2-tool", line 200, in subcommand_get_token args.output_file, File "/usr/bin/sasl-xoauth2-tool", line 183, in get_token_outlook tokens = outlook_get_initial_tokens(client_id, tenant, code) File "/usr/bin/sasl-xoauth2-tool", line 167, in outlook_get_initial_tokens headers={ "Content-Type": "application/x-www-form-urlencoded" })) File "/usr/lib64/python3.6/urllib/request.py", line 223, in urlopen return opener.open(url, data, timeout) File "/usr/lib64/python3.6/urllib/request.py", line 532, in open response = meth(req, response) File "/usr/lib64/python3.6/urllib/request.py", line 642, in http_response 'http', request, response, code, msg, hdrs) File "/usr/lib64/python3.6/urllib/request.py", line 570, in error return self._call_chain(args) File "/usr/lib64/python3.6/urllib/request.py", line 504, in _call_chain result = func(args) File "/usr/lib64/python3.6/urllib/request.py", line 650, in http_error_default raise HTTPError(req.full_url, code, msg, hdrs, fp) urllib.error.HTTPError: HTTP Error 401: Unauthorized

Kind regards,

JjF.

tarickb commented 1 year ago

Can you try updating to sasl-xoauth2 0.21, and then leaving the client secret blank?

JjfBcn commented 1 year ago

yum install sasl-xoauth2

Failed to set locale, defaulting to C Loaded plugins: fastestmirror, protectbase Loading mirror speeds from cached hostfile

should I compile? or maybe I don't have configured the right repo?

Kind regards,

JjF.

tarickb commented 1 year ago

Oh I didn't realize you're on RHEL/Fedora. Looking more carefully at your error message I think the problem is that you need to specify a client secret, but you're on an older version of sasl-xoauth2 that won't let you. Microsoft's documentation is pretty confusing about when a client secret is required for an initial token request, and specifying one when it isn't required will also result in a "401: Unauthorized" error.

Anyway -- for what you're trying to do, you don't actually need to build from source, you just need an updated helper script. Download sasl-xoauth2-tool at head and use it instead of the one installed at /usr/bin:

python3 ./sasl-xoauth2-tool.in get-token --client-id=foo --client-secret=bar --tenant=baz outlook ...
JjfBcn commented 1 year ago

Thank you for your help!

I suppose we've done something, we're not yet in the end...

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "/root/./sasl-xoauth2-tool.in", line 311, in main() File "/root/./sasl-xoauth2-tool.in", line 304, in main args.func(args) File "/root/./sasl-xoauth2-tool.in", line 204, in subcommand_get_token get_token_outlook( File "/root/./sasl-xoauth2-tool.in", line 184, in get_token_outlook tokens = outlook_get_initial_tokens(client_id, client_secret, tenant, code) File "/root/./sasl-xoauth2-tool.in", line 164, in outlook_get_initial_tokens resp = urllib.request.urlopen( File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 214, in urlopen return opener.open(url, data, timeout) File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 517, in open response = self._open(req, data) File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 534, in _open result = self._call_chain(self.handle_open, protocol, protocol + File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 494, in _call_chain result = func(*args) File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 1385, in https_open return self.do_open(http.client.HTTPSConnection, req, File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 1345, in do_open raise URLError(err) urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1123)>

Kind regards,

JjF.

tarickb commented 1 year ago

That looks like a Python environment issue? Can you make sure you're using the same Python environment as /usr/bin/sasl-xoauth2-tool is using? If you've got everything working properly this should give you "200":

$ python3 -c "import urllib.request; print(urllib.request.urlopen(urllib.request.Request('https://google.com/')).code)"
200

(It's a heavily-boiled-down reduction of the HTTP request code from the token tool.)

JjfBcn commented 1 year ago

It looks like you're correct...

python3 -c "import urllib.request; print(urllib.request.urlopen(urllib.request.Request('https://google.com/')).code)" Traceback (most recent call last): File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 1342, in do_open h.request(req.get_method(), req.selector, req.data, headers, File "/data/sfw/python/latest/lib/python3.9/http/client.py", line 1255, in request self._send_request(method, url, body, headers, encode_chunked) File "/data/sfw/python/latest/lib/python3.9/http/client.py", line 1301, in _send_request self.endheaders(body, encode_chunked=encode_chunked) File "/data/sfw/python/latest/lib/python3.9/http/client.py", line 1250, in endheaders self._send_output(message_body, encode_chunked=encode_chunked) File "/data/sfw/python/latest/lib/python3.9/http/client.py", line 1010, in _send_output self.send(msg) File "/data/sfw/python/latest/lib/python3.9/http/client.py", line 950, in send self.connect() File "/data/sfw/python/latest/lib/python3.9/http/client.py", line 1424, in connect self.sock = self._context.wrap_socket(self.sock, File "/data/sfw/python/latest/lib/python3.9/ssl.py", line 500, in wrap_socket return self.sslsocket_class._create( File "/data/sfw/python/latest/lib/python3.9/ssl.py", line 1040, in _create self.do_handshake() File "/data/sfw/python/latest/lib/python3.9/ssl.py", line 1309, in do_handshake self._sslobj.do_handshake() ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1123)

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "", line 1, in File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 214, in urlopen return opener.open(url, data, timeout) File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 517, in open response = self._open(req, data) File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 534, in _open result = self._call_chain(self.handle_open, protocol, protocol + File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 494, in _call_chain result = func(*args) File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 1385, in https_open return self.do_open(http.client.HTTPSConnection, req, File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 1345, in do_open raise URLError(err) urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1123)>

JjfBcn commented 1 year ago

Hi,

I've managed to avoid the certifacate validation (not a good pratice) but just to check that this is a solution I can use...

Finally we've succeeded in getting an initial token, that's good news, bad news is the token doesn't pass the test-token-refresh...

$ sasl-xoauth2-tool test-token-refresh ./prova.test\@sigmaaie.org Error from reader: * Line 5, Column 3 Missing ',' or '}' in object declaration sasl-xoauth2: Exception during init: reader error

But actually the line 5 seems to be correct, just a '}' and line 4, the last avoids the ','.

something like:

{ "access_token": "asdfasdfasdf", "refresh_token": "asdfasdfasdf", "expiry": 0 }

I suppose that check validation is a good reason to obtain this error when trying to send an email...

Jun 20 05:57:22 vtunelesexp postfix/qmgr[16617]: 51761E84A: from=prova.test@domain.com, size=878, nrcpt=1 (queue active) Jun 20 05:57:22 vtunelesexp postfix/smtp[30076]: sasl-xoauth2: Exception during init: reader error Jun 20 05:57:22 vtunelesexp postfix/smtp[30076]: warning: relayhost configuration problem Jun 20 05:57:22 vtunelesexp postfix/smtp[30076]: 51761E84A: to=jjf@domain.com, relay=none, delay=17378, delays=17377/0.05/0/0, dsn=4.3.5, status=deferred (unable to look up host smtp.office365.com: No address associated with hostname)

Any help will be appreciated.

Kind regards,

JjF.

JjfBcn commented 1 year ago

Hi again, and thank you for you help!

My fault! the error was in the config file, no in the token file. Once corrected we get this error:

$ sasl-xoauth2-tool test-token-refresh /etc/tokens/prova.test\@domain.com Config check passed. 2023-06-20 10:23:59: TokenStore::Read: file=/etc/tokens/prova.test@domain.com 2023-06-20 10:23:59: TokenStore::Read: refresh=0.asdñflkajsdflajsdfñalksjdfñlaskhdflkasjhdfaklsjhdfalkf-.asdfalksjdfhaksljdhfalskjdfh 2023-06-20 10:23:59: TokenStore::Refresh: attempt 1 2023-06-20 10:23:59: TokenStore::Refresh: token_endpoint: https://login.microsoftonline.com/consumers/oauth2/v2.0/token 2023-06-20 10:23:59: TokenStore::Refresh: request: client_id=1729348172124---* 2023-06-20 10:23:59: TokenStore::Refresh: code=400, response={"error":"invalid_grant","error_description":"AADSTS7000012: The grant was obtained for a different tenant.\r\nTrace ID: ****-b57e-45e6-af52-073247db0900\r\nCorrelation ID: *-a55b-4976-91a6-03df05ad70e7\r\nTimestamp: 2023-06-20 08:23:59Z","error_codes":[7000012],"timestamp":"2023-06-20 08:23:59Z","trace_id":"4eb495d5-*-45e6--073247db0900","correlation_id":"**-a55b-4976-****-03df05ad70e7"} 2023-06-20 10:23:59: TokenStore::Refresh: request failed

Kind regards,

JjF.

JjfBcn commented 1 year ago

Hi,

After making some changes to the App in Azure now we get this error:

$ sasl-xoauth2-tool test-token-refresh /etc/tokens/prova.test\@domain.com

2023-06-20 16:49:37: TokenStore::Refresh: code=401, response={"error":"invalid_client","error_description":"AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'.\r\nTrace ID: 0****-***-4301-a10f-3c5b6e762b00\r\nCorrelation ID: 51ea17c8-6078-4cdb-8509-e5fd435a37b2\r\nTimestamp: 2023-06-20 14:49:37Z","error_codes":[7000218],"timestamp":"2023-06-20 14:49:37Z","trace_id":"0f59ad67-9520-4301-a10f-3c5b6e762b00","correlation_id":"51ea17c8-6078-4cdb-8509-e5fd435a37b2","error_uri":"https://login.microsoftonline.com/error?code=7000218"} 2023-06-20 16:49:37: TokenStore::Refresh: request failed

Any ideas?

Kind regards,

JjF.

tarickb commented 1 year ago

Are you specifying client_secret in /etc/sasl-xoauth2.conf?

JjfBcn commented 1 year ago

Yes. I've done in the 3 ways, specifying the client_secret in the sasl-xoauth2.conf, leaving it blank and specifying when then script requests and in the file and at the script request.

I've tried with mobile and desktop application Authentication Platform and with Web Platform.

Both resulting in File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 641, in http_error_default raise HTTPError(req.full_url, code, msg, hdrs, fp) urllib.error.HTTPError: HTTP Error 401: Unauthorized

or AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'.

I'm not doing something right, but is hard to put all pieces in the right position...

JjfBcn commented 1 year ago

Currently I'm stuck in the situation:

The result is, when genrate the inital token, when pasting the Resulting URL I get: Traceback (most recent call last): File "/root/./sasl-xoauth2-tool.in", line 314, in main() File "/root/./sasl-xoauth2-tool.in", line 307, in main args.func(args) File "/root/./sasl-xoauth2-tool.in", line 207, in subcommand_get_token get_token_outlook( File "/root/./sasl-xoauth2-tool.in", line 187, in get_token_outlook tokens = outlook_get_initial_tokens(client_id, client_secret, tenant, code) File "/root/./sasl-xoauth2-tool.in", line 167, in outlook_get_initial_tokens resp = urllib.request.urlopen( File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 214, in urlopen return opener.open(url, data, timeout) File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 523, in open response = meth(req, response) File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 632, in http_response response = self.parent.error( File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 561, in error return self._call_chain(args) File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 494, in _call_chain result = func(args) File "/data/sfw/python/latest/lib/python3.9/urllib/request.py", line 641, in http_error_default raise HTTPError(req.full_url, code, msg, hdrs, fp) urllib.error.HTTPError: HTTP Error 401: Unauthorized

The result is, when genrate the inital token, when pasting the Resulting URL the initial token is generated without problem.

But, testing the refresh token I get the error:

$ sasl-xoauth2-tool test-token-refresh /etc/tokens/prova.test\@domain.com Config check passed. 2023-06-21 01:34:02: TokenStore::Read: file=/etc/tokens/prova.test@domain.com 2023-06-21 01:34:02: TokenStore::Read: refresh=dddddddddaadadad, access=asdfasdfasdfadfadf 2023-06-21 01:34:02: TokenStore::Refresh: attempt 1 2023-06-21 01:34:02: TokenStore::Refresh: token_endpoint: https://login.microsoftonline.com/<TenantID>/oauth2/v2.0/token 2023-06-21 01:34:02: TokenStore::Refresh: request: client_id=*******&client_secret=c*******&grant_type=refresh_token&refresh_token=xxxxxxxxx 2023-06-21 01:34:02: TokenStore::Refresh: code=401, response={"error":"invalid_client","error_description":"AADSTS700025: Client is public so neither 'client_assertion' nor 'client_secret' should be presented.\r\nTrace ID: bf1493c0-cccd-4133-b8bf-36e31a452100\r\nCorrelation ID: 421cbfb5-e455-480f-a574-2001646dd83e\r\nTimestamp: 2023-06-20 23:34:02Z","error_codes":[700025],"timestamp":"2023-06-20 23:34:02Z","trace_id":"bf1493c0-cccd-4133-b8bf-36e31a452100","correlation_id":"421cbfb5-e455-480f-a574-2001646dd83e"} 2023-06-21 01:34:02: TokenStore::Refresh: request failed Token refresh failed.

In both cases the secret is in the /etc/sasl-xoauth2.conf file.

Any help will be appreciated.

kind regards,

JjF.

tarickb commented 1 year ago

The logs from that second experiment you ran suggest that you shouldn't include the client secret in /etc/sasl-xoauth2.conf: "Client is public so neither 'client_assertion' nor 'client_secret' should be presented". Have you tried requesting the initial token the same way but just leaving client_secret blank in the config file?

Sorry for all the guesswork here, but like I mentioned earlier it's been hard to get clarity from the Microsoft docs on when a secret is actually required.

tarickb commented 11 months ago

If you're still having trouble with this issue, please try the device-flow option in sasl-xoauth 0.23. Full instructions are in the README but basically you need to enable "Allow public client flows" for your app registration (in the Azure console), and pass --use-device-flow to sasl-xoauth2-tool.