gpsoauth icon indicating copy to clipboard operation
gpsoauth copied to clipboard

Consistently getting BadAuthentication

Open stevearc opened this issue 1 year ago • 33 comments

The same effect as #24, though possibly a different cause. Every time I do gpsoauth.perform_master_login() I receive a BadAuthentication error. This happens for a normal password protected account as well as 2FA using an app password. This is also happening to @kaddkaka , so slightly less chance that it's just something weird with my account. Has Google changed something in their API recently?

OS: linux Python: 3.10.4 pip freeze:

certifi==2022.9.14
cffi==1.15.1
charset-normalizer==2.1.1
cryptography==38.0.1
future==0.18.2
gkeepapi==0.14.2
gpsoauth==1.0.2
idna==3.4
jaraco.classes==3.2.2
jeepney==0.8.0
keyring==23.9.3
keyrings.alt==4.2.0
more-itertools==8.14.0
pycparser==2.21
pycryptodomex==3.15.0
requests==2.28.1
SecretStorage==3.3.3
urllib3==1.26.12

stevearc avatar Sep 20 '22 11:09 stevearc

A test login just worked for me. I also tried that version of urllib3.

simon-weber avatar Sep 22 '22 15:09 simon-weber

Hmmm...maybe something odd is going on with both repro accounts then. If you don't mind, I'll leave this issue open for a bit longer and try to do some more investigation.

stevearc avatar Sep 24 '22 08:09 stevearc

i didn't have time to look into the cause, but i had this exact same problem when i was trying to use the library on ubuntu. however, it worked fine in windows. can you try a different platform?

jnperry avatar Oct 09 '22 07:10 jnperry

Were they two different machines? Sometimes Google will do a mandatory mfa step when it sees a new device, which I think results in BadAuth (I can't remember).

simon-weber avatar Oct 09 '22 15:10 simon-weber

I have only tried this from my Ubuntu 22.04 machine, and I just get the BadAuthentication. Not sure what I can do to investigate further.

kaddkaka avatar Oct 17 '22 20:10 kaddkaka

There's no logging of the responses or anything (since they might be sensitive) but you could hack that into your local code and hopefully get more information on why the request is failing. The code is pretty simple: https://github.com/simon-weber/gpsoauth/blob/master/gpsoauth/init.py

simon-weber avatar Oct 17 '22 21:10 simon-weber

sorry, it was the same machine. i use my google account regularly on both linux and windows on that computer, so not sure. i only mentioned it because i saw another post on another project (sorry, i can't find it anymore) that mentioned several people were having trouble with this auth on the latest ubuntu

jnperry avatar Oct 17 '22 21:10 jnperry

I tried again on my non-work laptop with an account that does not have 2-factor enabled, and the login worked. Before when I was testing it I was traveling, so it's entirely possible that Google was blocking access because the traffic looked suspicious. @kaddkaka I think your best bet is Simon's suggestion to add more logging to gpsoauth and see if you can find more information. Initially I thought this could be a gpsoauth issue since it was happening to me as well (it's worked without issue for a long time), but now it seems more likely that it's some account-specific problem.

stevearc avatar Oct 19 '22 04:10 stevearc

Same issue when I tried to login with app password (my account has 2FA enabled).


Update: OK it failed when I was using the Python3.9 that came with MacOS.
However, it worked then after I use Python3.10 installed via homebrew! Not sure what's the root cause here though.

markx avatar Nov 15 '22 17:11 markx

Same issue when I tried to login with app password (my account has 2FA enabled).

Update: OK it failed when I was using the Python3.9 that came with MacOS. However, it worked then after I use Python3.10 installed via homebrew! Not sure what's the root cause here though.

Unfortunately, it doesn't work for me

Shonke avatar Dec 13 '22 07:12 Shonke

We are facing the same problem with the package that relies on gpsoauth (related to https://github.com/leikoilja/ha-google-home/issues/599).

Seems that I was just able to replicate the issue. Authentication works fine on the Mac M1 machine with OpenSSL 1.1.1j 16 Feb 2021 (openssl version), but on Ubuntu 22.04 with OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022) I am hit with BadAuthentication. @simon-weber, do you think you can try the same? I just spun the VM with ubuntu 22.04, checked openssl version (verify with python -c "import ssl; print(ssl.OPENSSL_VERSION)" that it's OpenSSL 3.0.2) and was able to replicate the issue. ping @KapJI

leikoilja avatar Mar 12 '23 14:03 leikoilja

Cool, I can repro with openssl 3. Switching from EncryptedPasswd to Passwd works on the old openssl but not the new one, so my guess is urllib3 is doing something different with the tls that Google doesn't like. This happened once before in https://github.com/urllib3/urllib3/issues/2101.

simon-weber avatar Mar 13 '23 17:03 simon-weber

Does this script work as of May, 2023? Or Google has changed something that makes this script not working? I have tried the steps that are posted in this issue and none of them have worked for me

Tony450 avatar May 10 '23 10:05 Tony450

It worked for me just now on openssl 1.

simon-weber avatar May 10 '23 21:05 simon-weber

so what did you do? did you import something else? installed something? or set some configuration?

engdorm avatar Jun 15 '23 18:06 engdorm

In my case it finally worked with OpenSSL 1. I used Kali Linux 2021.2 (in which OpenSSL 1 is not changed by OpenSSL 3 and has Python 3.9.2 by default). I tried to change from OpenSSL 3 to OpenSSL 1 in another virtual machine (the last version of Kali) but none of the guides published out there worked for me. It was easier to just install an older distribution that came with OpenSSL 1.

Tony450 avatar Jun 16 '23 15:06 Tony450

Still the same:

  • urllib3==1.26.16 with OpenSSL 1 working fine
  • urllib3-2.0.3 with OpenSSL 1 giving no attribute 'DEFAULT_CIPHERS'
  • urllib3==1.26.16 with OpenSSL 3 giving {'Error': 'BadAuthentication'}
  • urllib3-2.0.3 with OpenSSL 3 giving no attribute 'DEFAULT_CIPHERS'

So, maybe it's time to fix DEFAULT_CIPHERS issue https://github.com/simon-weber/gpsoauth/issues/52?

artickl avatar Jul 05 '23 22:07 artickl

Hi All!

I'd like to hijack this issue as i had the BadAuthentication problem myself on Linux but not on Windows. As Google in their infinite wisdom decided to kill the integration to custom shopping list providers I had a huge motivation to get my sync running so i sunk a few hours into that problem.

What I noticed is that on linux the EncryptedPasswd string was terminated with a \n while on windows it wasn't.

Easy but ugly fix: within init.py modify _perform_auth_request and just strip it off if it is there

   session.headers = {
        "User-Agent": USER_AGENT,
        "Content-type": "application/x-www-form-urlencoded",
    }                        
    if data["EncryptedPasswd"].endswith("\n"):
        data["EncryptedPasswd"]=data["EncryptedPasswd"][:-1]
        print("RemovedNewline")
    res = session.post(AUTH_URL, data=data, verify=True)

Done that and it just works every time now. I hope that helps some of you

best regards

Michael

miccico avatar Jul 12 '23 21:07 miccico

Can someone with the openssl v3 issue try this and see if it helps?

simon-weber avatar Jul 14 '23 17:07 simon-weber

@simon-weber / @miccico,

Sorry, I checked on both versions by adding a new test into pytest "test_48.py" (I didn't commit anything, because I did not see a value in it):

gpsoauth$ cat tests/test_48.py
"""Tests for issue 48: 'Consistently getting BadAuthentication #48'"""

import gpsoauth

def test_master_key() -> None:
    email = '[email protected]'
    password = 'my-password'
    android_id = '0123456789abcdef'

    master_response = gpsoauth.perform_master_login(email, password, android_id)
    print(master_response)

    assert master_response == "{'Error': 'BadAuthentication'}

Works well as is for urllib3==1.26.5 with OpenSSL 1.1.1:

(gpsoauth-py3.9) artickl@penguin:~/git/github/gpsoauth$ cat /etc/debian_version 
11.7
(gpsoauth-py3.9) artickl@penguin:~/git/github/gpsoauth$ dpkg --list | grep -e "openssl " -e "python3-urllib3"
ii  openssl                           1.1.1n-0+deb11u5               amd64        Secure Sockets Layer toolkit - cryptographic utility
ii  python3-urllib3                   1.26.5-1~exp1                  all          HTTP library with thread-safe connection pooling for Python3

gpsoauth$ pytest
=================================== test session starts ===================================
platform linux -- Python 3.9.2, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: ..../gpsoauth
collected 3 items                                                                         

tests/test_48.py F                                                                  [ 33%]
tests/test_all.py ..                                                                [100%]
================================= short test summary info =================================
FAILED tests/test_48.py::test_master_key - assert {'Error': 'NeedsBrowser', 'ErrorDetail...

But still failing with {'Error': 'BadAuthentication'} on urllib3==1.26.5 with OpenSSL 3.0.2:

gpsoauth$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04.2 LTS"

gpsoauth$ dpkg --list | grep -e "openssl " -e "python3-urllib3"
ii  openssl                               3.0.2-0ubuntu1.10                       amd64        Secure Sockets Layer toolkit - cryptographic utility
ii  python3-openssl                       21.0.0-1                                all          Python 3 wrapper around the OpenSSL library
ii  python3-urllib3                       1.26.5-1~exp1                           all          HTTP library with thread-safe connection pooling for Python3

gpsoauth$ pytest 
=================================== test session starts ===================================
platform linux -- Python 3.10.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: ..../gpsoauth
collected 3 items                                                                         

tests/test_48.py F                                                                  [ 33%]
tests/test_all.py ..                                                                [100%]
==================================== warnings summary =====================================
tests/test_48.py::test_master_key
  /home/lenovo/git/github-personal/gpsoauth/gpsoauth/__init__.py:75: DeprecationWarning: ssl.SSLContext() without protocol argument is deprecated.
    context = SSLContext()

tests/test_48.py::test_master_key
  /home/lenovo/git/github-personal/gpsoauth/gpsoauth/__init__.py:75: DeprecationWarning: ssl.PROTOCOL_TLS is deprecated
    context = SSLContext()

-- Docs: https://docs.pytest.org/en/stable/warnings.html
================================= short test summary info =================================
FAILED tests/test_48.py::test_master_key - assert {'Error': 'BadAuthentication'} == "{'Error': 'BadAuthentication'}"
========================= 1 failed, 2 passed, 2 warnings in 0.40s =========================

Tests are giving the same result on Jun 1 commit without any additional changes:

gpsoauth$ git log
commit b22c57a236eb0bd63517cb4c1bf35d3fca35e2c7 (HEAD -> master, origin/master, origin/HEAD)
Author: Simon Weber <[email protected]>
Date:   Thu Jun 1 21:18:38 2023 -0400

    appease linters

And with changes based on @miccico suggestion give the same BadAuthentication result:

gpsoauth$ git diff gpsoauth/__init__.py
diff --git a/gpsoauth/__init__.py b/gpsoauth/__init__.py
index a9b2378..bacb4ed 100644
--- a/gpsoauth/__init__.py
+++ b/gpsoauth/__init__.py
@@ -94,6 +94,11 @@ def _perform_auth_request(
         }
     )
 
+    print(data["EncryptedPasswd"])
+    if data["EncryptedPasswd"].decode().endswith(tuple("\n")):
+        data["EncryptedPasswd"]=data["EncryptedPasswd"][:-1]
+        print("RemovedNewline")
+
     res = session.post(AUTH_URL, data=data, verify=True)
 
     return google.parse_auth_response(res.text)

artickl avatar Jul 17 '23 18:07 artickl

Thanks for testing it out! It looks like that fixes a separate issue from the openssl one.

simon-weber avatar Jul 18 '23 15:07 simon-weber

Hi all,

I'm having the same issue. It's a bummer because there are a bunch of downstream projects getting hit with the same problem as well and this is clearly a project used by a lot of other libraries.

@simon-weber would it be possible to get a summary of the state of the world on this bug? What you think the root cause is and any possible fixes? I'm running this in Home Assistant so fixes that can be done in an environment where I have a shared OS with other dependencies would also be appreciated.

Eric

ELind77 avatar Jul 30 '23 22:07 ELind77

My guess is that this is something like https://github.com/urllib3/urllib3/issues/2101, where a) Google is picky about tls params and b) using openssl v3 shifts them to something Google doesn't like. If someone wants to test that, they can set up a debugging https proxy and compare a working request to a non-working one.

As a workaround you can use a pre-v3 openssl version.

simon-weber avatar Jul 31 '23 20:07 simon-weber

Here's my solution for the moment:

gpsoauth_login.Dockerfile

FROM alpine:3.16
RUN apk upgrade --update-cache --available && \
    apk add python3 py3-pip && \
    pip install gpsoauth 'urllib3<=1.25.11'
RUN echo $'import gpsoauth; import json\n\
ret = gpsoauth.perform_master_login(input(), input(), input())\n\
print(json.dumps(ret))' > /glogin.py
ENTRYPOINT ["python3", "/glogin.py"]

Usage:

$ docker build -t gpsoauth_login -f gpsoauth_login.Dockerfile .
$ docker run -it --rm gpsoauth_login
<stdin: username>
<stdin: password>
<stdin: android_id>
{'SID': 'BAD_COOKIE', 'LSID': 'BAD_COOKIE', 'Token': ... }

Save your token somewhere, and get your application to use that instead of calling perform_master_login directly.

Here's an example of saving the token directly into your keyring:

(Python) https://gist.github.com/jkitching/57baead775f6773848d2e334cc950999 (Bash) https://gist.github.com/jkitching/1e6bab9e3fd935aca2169528cd7eb497

jkitching avatar Aug 23 '23 17:08 jkitching

Here's my solution for the moment:

gpsoauth_login.Dockerfile

FROM alpine:3.16
RUN apk upgrade --update-cache --available && \
    apk add python3 py3-pip && \
    pip install gpsoauth 'urllib3<=1.25.11'
RUN echo $'import gpsoauth; import json\n\
ret = gpsoauth.perform_master_login(input(), input(), input())\n\
print(json.dumps(ret))' > /glogin.py
ENTRYPOINT ["python3", "/glogin.py"]

Usage:

$ docker build -t gpsoauth_login -f gpsoauth_login.Dockerfile .
$ docker run -it --rm gpsoauth_login
<stdin: username>
<stdin: password>
<stdin: android_id>
{'SID': 'BAD_COOKIE', 'LSID': 'BAD_COOKIE', 'Token': ... }

Save your token somewhere, and get your application to use that instead of calling perform_master_login directly.

Here's an example of saving the token directly into your keyring:

(Python) https://gist.github.com/jkitching/57baead775f6773848d2e334cc950999 (Bash) https://gist.github.com/jkitching/1e6bab9e3fd935aca2169528cd7eb497

Can't get it to work without androidid. If only the script would pause and let me do the URL thing.

VNRARA avatar Sep 27 '23 22:09 VNRARA

Here's my solution for the moment:

gpsoauth_login.Dockerfile

FROM alpine:3.16
RUN apk upgrade --update-cache --available && \
    apk add python3 py3-pip && \
    pip install gpsoauth 'urllib3<=1.25.11'
RUN echo $'import gpsoauth; import json\n\
ret = gpsoauth.perform_master_login(input(), input(), input())\n\
print(json.dumps(ret))' > /glogin.py
ENTRYPOINT ["python3", "/glogin.py"]

Usage:

$ docker build -t gpsoauth_login -f gpsoauth_login.Dockerfile .
$ docker run -it --rm gpsoauth_login
<stdin: username>
<stdin: password>
<stdin: android_id>
{'SID': 'BAD_COOKIE', 'LSID': 'BAD_COOKIE', 'Token': ... }

Save your token somewhere, and get your application to use that instead of calling perform_master_login directly.

Here's an example of saving the token directly into your keyring:

(Python) https://gist.github.com/jkitching/57baead775f6773848d2e334cc950999 (Bash) https://gist.github.com/jkitching/1e6bab9e3fd935aca2169528cd7eb497

@jkitching your solution is brilliant, but it does not work (anymore?) unfortunately.

Instead of the token, I get this: {"Error": "NeedsBrowser", "Url": "https://accounts.google.com/signin/continue?sarp=1&scc=1&continue=https://accounts.google.com/o/android/auth?hl%3Den_us%26xoauth_display_name%3DAndroid%2BLogin%2BService%26source%3DAndroid%2BLogin&plt=VERY_LONG_TOKEN_REDACTED", "ErrorDetail": "To access your account, you must sign in on the web. Touch Next to start browser sign-in."}

I tried to make it work by opening the url with a browser, it seems to work as it asks me to confirm my login details, but then I get a static page telling me to "wait a moment", which doesn't lead anywhere (i.e. it waits forever).

Any suggestions?

Cris70 avatar Oct 18 '23 08:10 Cris70

@Cris70 I can't seem to reproduce on my end... it still happily hands me a valid token.

Are you using 2FA? Perhaps you need to set up an App Password as suggested here? https://github.com/PiotrMachowski/Home-Assistant-custom-components-Google-Keep/issues/3

jkitching avatar Oct 18 '23 09:10 jkitching

@jkitching I am using 2FA and I am using an app password. No joy unfortuantely. I tried generating another app password, but the same happened.

p.s. If you have read my previous reply, that was meant for another thread. I am writing on multiple issues and I am messing things up a bit 😅

Cris70 avatar Oct 18 '23 09:10 Cris70

I spent some time debugging it and the only difference in working and broken environments was ffdhe in supported groups in TLS Client Hello packet. But I haven't found a way to change that using SSLContext.

E.g. in Python 3.8 it works with OpenSSL 1.1.1o but in Python 3.11 which adds ffdhe with OpenSSL 3.0.12 it fails with BadAuthentication.

KapJI avatar Nov 06 '23 17:11 KapJI

Nice find! That seems like something we should be able to configure.

simon-weber avatar Nov 07 '23 19:11 simon-weber