Skip to content
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

authentication on raspberry pi #8

Closed
thomasjetzinger opened this issue Oct 16, 2015 · 12 comments
Closed

authentication on raspberry pi #8

thomasjetzinger opened this issue Oct 16, 2015 · 12 comments

Comments

@thomasjetzinger
Copy link

I want to use the new onedrive-sdk with my raspberry pi running raspbian, but i have problems to acquire the authentication code.
As we can see in the source code the authenticater uses the webbrowser.open command to get the authentication code, so i tried to install Lynx to get this command working,
But each time my program calls GetAuthCodeServer.get_auth_code(auth_url, redirect_uri), the following error is printed to the console:
Error opening terminal: emacs Error opening terminal: emacs.

Is it even possible to authenticate without a graphical browser?

Best Regards,
Thomas

@cdmayer
Copy link
Contributor

cdmayer commented Oct 16, 2015

Hello Thomas,

The GetAuthCodeServer module does assume that there is a usable browser. It is definitely possible to use the SDK with a Raspberry Pi, but since the screen is so small you'll have to do a bit more work. It is not possible at this time to do initial app authorization without a browser. Here's how I would work around that.

  1. Use the script below on a computer with a web browser to get through the initial code acquisition. That's the only part where a browser is required.
    • Make sure that you include wl.offline_access in your scopes requested. That will give you a refresh token, which you will need later.
  2. Transfer the code in the response from the auth server over to your Pi. The best way to do that will depend on how you develop on your Pi.
  3. Use the code in client.auth_provider.authenticate(). After that call, your client is authenticated, and any calls to the API should succeed.
  4. Use auth_provider.save_session() to save the session information for later. Then, at the beginning of every session, just use load_session() and refresh_token() to get new tokens. You'll never need to use a browser again!

A caution on step (4): the default implementation of the Session object is NOT safe for use anywhere other than development. It saves your auth key to a .pickle file, which is basically like saving your password into a .txt file. If you want to use this in a more serious application, I would recommend subclassing the Session object to use a safer form of storage.

Let me know if you have any questions! I'm glad to hear someone is using the API on a Raspberry Pi. I'd love to see whatever you end up making!

Code for Step (1):

import onedrivesdk
from onedrivesdk.helpers import GetAuthCodeServer

if __name__ == "__main__":
    client_id = "{your_client_id}"
    redirect_uri = "http://localhost:8080/"

    client = onedrivesdk.get_default_client(client_id=client_id,
                                            scopes=['onedrive.readwrite',
                                                    'wl.signin',
                                                    'wl.offline_access'])

    auth_url = client.auth_provider.get_auth_url(redirect_uri)

    # Block thread until we have the code
    code = GetAuthCodeServer.get_auth_code(auth_url, redirect_uri)
    print("Token available as 'code' local var, and here:\n")
    print(code)    

@cdmayer
Copy link
Contributor

cdmayer commented Oct 16, 2015

PS the redirect_uri you use in the initial auth and on your Pi must match or the auth code won't work.

@kevinsul
Copy link

So complete newbie here... Messing with an RPi and simply wish to upload a few files via Python script. I was able to get some of the above working, howeer, it seems that when I issue the 'code = client.auth_provider...' command in my script, it fires up my default browser on the RPi (Epiphany) and shows me the code embedded in the URL, but then freezed execution of my script there. If I am quick enough, I can copy/paste the code from the URL, hardcode this into my 'code' value and can then successfully authenticate. If I could just figure out how to get the 'code = client.auth_provider...' to execute and continue with my script, I would be good to go. Any ideas? Perhaps I need a more complete example.

@thomasjetzinger
Copy link
Author

Thanks for your reply...
Authentication via another system which includes a full web browser works, but i have problems to load the stored session:
Each time I call client.auth_provider.load_session() the following exception is raised:
unbound method load_session() must be called with Session instance as first argument (got nothing instead).
Is there problem with python 2.7? How can i get this working?

@cdmayer
Copy link
Contributor

cdmayer commented Oct 19, 2015

How did you create your client? Did you use the extension method get_default_client()? It seems like something isn't initialized. It shouldn't be a Python 2-specific error because this uses the same code as Python 3.

@cdmayer
Copy link
Contributor

cdmayer commented Oct 19, 2015

Kevin, I would not recommend that you use the GetAuthCodeServer module on a Pi at all. That module was designed for a debugging/testing on a richer environment like Windows or Mac OS. It relies on spinning up a webserver on another thread, then executing an HTTP request on the current thread, then killing other thread. That module hasn't been tested on a Pi so I can't recommend it.

Like I recommended to Thomas, I would say you should get your auth code any way you feel comfortable, then make sure to save your first session. From there you can just keep refreshing your token and never need to get an auth code again.

@thomasjetzinger
Copy link
Author

Yes, i use the method get_default_client like in the following code snippet:

redirect_uri = "http://localhost:8080/"
client_secret = "xxx"

client = onedrivesdk.get_default_client(client_id='xxx',
                                        scopes=['wl.signin',
                                                'wl.offline_access',
                                                'onedrive.readwrite'])
client.auth_provider.load_session()

The exception occurs in the following method:
image

@cdmayer
Copy link
Contributor

cdmayer commented Oct 19, 2015

I stand corrected. It does appear to be a Python 2 issue. I have identified the fix, which I'll bring in soon. Until then, can you make this small change and see if it works? Open the following file: %Python27dir%\Lib\site-packages\onedrivesdk\session.py then add the following decorator:

@staticmethod
    def load_session(**load_session_kwargs):

Please try that again and let me know if it works or not. It worked for me.

cdmayer added a commit that referenced this issue Oct 19, 2015
@thomasjetzinger
Copy link
Author

Now it works! When will you provide the new python package?

@cdmayer cdmayer closed this as completed Oct 21, 2015
@RaspiRepo
Copy link

Getting authentication access from onedrive without browser interaction can be done with Web driver phantomjs and Selenium. This allows to paring HTML response page from one page and authenticate, programmatically. This allows no user input like type username, password and give authorization.
Here is the python code to do same on Raspberry PI.

To install phantomjs webdriver (for headlness node) on raspberry pi please google it.

author = 'Mariya'
import onedrivesdk
from selenium import webdriver

#Onedrive Access code from control panel
redirect_uri = "https://login.live.com/oauth20_desktop.srf"

#replace this value from your one drive developer panel.
client_secret = "client secret"
client_id_str = "client_idstr"

user_name = 'email_adress'
password = 'password'

client = onedrivesdk.get_default_client(client_id=client_id_str,
scopes=['wl.signin',
'wl.offline_access',
'onedrive.readwrite'])
auth_url = client.auth_provider.get_auth_url(redirect_uri)
driver = webdriver.PhantomJS() # 'phantomjs')

"""
driver = webdriver.Chrome('chromedriver')
driver.set_window_size(1, 1)
"""

driver.get(auth_url)
driver.implicitly_wait(15)

login_field = driver.find_element_by_name("loginfmt")
password_field = driver.find_element_by_name("passwd")
sign_btn = driver.find_element_by_id("idSIButton9")

Fill user name and password

login_field.send_keys(user_name)
password_field.send_keys(password)
sign_btn.click()
element = driver.find_element_by_name('ucaccept')
element.click()

parse URL to get code and close the browser

tokens = driver.current_url.split('=')
driver.quit()

print(tokens[1].split('&')[0])

access_code = tokens[1].split('&')[0]
print("access code is here ", access_code)

@cdmayer
Copy link
Contributor

cdmayer commented Apr 4, 2016

This is definitely interesting. It basically pretends to be a web browser and submits the form. It's fragile, but then anything like this will tend to be fragile.

If you submit a pull request with this code we can work on getting it merged into the main package! I would start with a new file in the /helpers directory. Perhaps GetAuthCodeHeadless.py?

@RaspiRepo
Copy link

Hi Chris,
Thanks for feedback. Yes I agree that its fragile as any time web forms filed (custom names) changes need track the HTML form fields. I am new to GitHub but I will try to pull request and submit entire code back.

I written this method for Raspberry PI project to capture picture/Video (surveillance as just outdoor view) when motion detected and upload to One Drive 24/7. Since Raspberry PI not connected with any monitor so has to crack the website OR workaround this way.

I am just curious!, is there any other or future plan to allow authentication without browser UI ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants