MisterWil / abodepy

A thin Python wrapper for the Abode alarm API
MIT License
50 stars 17 forks source link

Support 2FA #32

Closed MisterWil closed 4 years ago

MisterWil commented 6 years ago

Abode now supports 2FA. This ties in to issue #30 which requires a UUID for login requests now. I assume this UUID is to allow Abode to keep track of which 'devices' have logged in previously and used 2FA to complete the process.

I'll need to enable 2FA on my account and then I'll note the new packets that are used to complete this login process. I'll also need to save this UUID somewhere - probably the new config file option as per #20.

gilphilbert commented 4 years ago

Hi, I have worked this out and it's not very complex:

The login body can optionally contain the field field: mfa_code. If the user has 2FA turned on and this field is not supplied, your API request to login will return status code 200 with the following data: { mfa_type: 'google_authenticator' }

This prompts you to supply the 2FA code, in this case from Google Authenticator (which I think is the only one currently supported). Once the mfa_code field is supplied (and correct) then login continues as normal.

To prevent the 2FA code requirement for every login, set the field remember_me to 1 during login.

MisterWil commented 4 years ago

Ah, awesome, glad it isn't difficult on the Abode side of things. I know its more complicated on the Home Assistant side (need some UI flow and the component has changed quite a bit thanks to the work of @shred86).

Mostly I haven't bothered to do this since I think the easiest solution it to just create a linked family account with strong password for the Home Assistant component and then enable 2FA for all other accounts.

shred86 commented 4 years ago

I briefly looked into this and it's probably something I could figure out on the HA side, but my understanding is with 2FA, you will eventually be prompted for a new mfa_code even with remember_me set to 1. The issue with that is obviously at some point it would break the integration and you will have to log back in. Based on that, I decided it's probably not worth the effort. I wish Abode offered something like access tokens and/or a way to integrate with their devices locally.

MisterWil commented 4 years ago

Local would be 💯 🔥 but at this point I suspect it'll never happen.

kevdliu commented 4 years ago

I recently got into home assistant and abode and would like to give this a shot for fun. I'm currently trying to figure out how abode is identifying the client used to login. I assumed it would be the UUID, but from looking at the network requests when signing in with my normal browser and when signing in with incognito, it looks like the UUID in both cases are the same, even though I got gated by MFA in incognito but not the normal browser. I did see the response with mfa_type like gilphilbert mentioned when in incognito, but when I tried to login with abodepy, i got a 401 unauthorized instead of the 200. I even tried copying the browser UUID into abodepy but got the same result. I'm wondering if you guys have any insight into this. Also feel free to ignore me since this is a pretty old topic.

kevdliu commented 4 years ago

I just had another thought. What if we used something like pyotp to generate and supply the actual MFA code when signing in? We can use a QR code reader to extract the OTP seed/secret from abode's qr code and then use that to generate MFA codes. One downside is that existing users would have to disable and re-enable MFA on their abode account in order to extract the secret (and the fact that we'll be storing it on disk, but we're already storing the password the same way ¯_(ツ)_/¯), but I think the security benefits are worth it.

MisterWil commented 4 years ago

I've not looked into this any closer because I don't use it, and frankly I don't see any point to it since you can just add another user for automations with a complex password that doesn't have 2FA set up, and then you set up 2FA on your regular user accounts where it would actually matter (since those logins might be from new devices and are more susceptible to brute forcing or password leaks). The benefit of this is that your timeline will have a distinct user for when things are changed instead of looking as if it happened from a real user. Plus, you can name your automation account "Jeeves". 😆

As for how the flow should work if this were to ever get implemented is this:

1) Use the Abode app or webapp to set up 2FA with Google Authenticator or other 2FA app (I use Authy, for example) 2) When you login with this library the first time to an account with 2FA without your 2FA code, you would get back a response from the Abode API to indicate you need a 2FA code. 3) A second login attempt would then need to be made, passing in your current 2FA pin.

I'm honestly not sure what abode uses to identify what the same device is. I would assume it's a combination of the UUID as well as perhaps the user agent? Maybe it uses cookies/sessions to know if you've logged in before, given that you've indicated that the UUID is apparently the same in incognito but the 2FA login wasn't remembered?

kevdliu commented 4 years ago

Thanks for explaining the flow, it sounds like maybe the library needs to persist the requests session to disk. You're right about having a sub-account for automations, that's how I have my setup right now. My thought was to actually enable 2FA on the automation account as well. Can't hurt to have another layer of protection, especially since it doesn't look like Abode sends email notifications for logins from unknown devices. I'll play around with this more for fun, maybe one day it'll mature into a PR. Thanks for creating this library btw it's 🔥

kevdliu commented 4 years ago

Quick update if you're interested. The client is uniquely identified by the UUID and a "SESSION" cookie. After persisting the session cookies to disk, I was able to load them into requests.session during subsequent logins and access my mfa enabled abode account.

MisterWil commented 4 years ago

Great to know! I'm already persisting things like the UUID and the access token to disk in a pickle file, so it likely wouldn't be too much more work to just go ahead and persist the session too. :-)

kevdliu commented 4 years ago

Yeah that's the approach I went with. I created a draft PR for some early feedback if you want to take a look https://github.com/MisterWil/abodepy/pull/76

MisterWil commented 4 years ago

I'll definitely take a look when I get a bit of free time... likely Friday since I have the day off. Make sure to write tests! :-D

kevdliu commented 4 years ago

Added some tests and fixed a bunch of pylink issues 👍

MisterWil commented 4 years ago

Added in 1.2.0