I'm trying to authenticate to SharePoint Online. Using sharepy v 2.0, pyCharm community edition, and python 3.9.
When I run:
'sharepy.connect('siteurl')'
From within PyCharm, Sharepy will freeze after I input my username in the run dialog box.
If I add the 'username' parameter and run it. Nothing happens. I'm never prompted for a password
If I use the console and enter in sharepy.connect('siteurl') then username and password (same goes for passing those parameters) I will get an error:
Traceback (most recent call last):
File "C:\Users\Andrew\AppData\Local\Programs\Python\Python39\lib\site-packages\sharepy\auth\adfs.py", line 75, in _get_token
token = root.find('.//wsse:BinarySecurityToken', ns).text
AttributeError: 'NoneType' object has no attribute 'text'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\Andrew\AppData\Local\Programs\Python\Python39\lib\code.py", line 90, in runcode
exec(code, self.locals)
File "<input>", line 1, in <module>
File "C:\Users\Andrew\AppData\Local\Programs\Python\Python39\lib\site-packages\sharepy\session.py", line 15, in connect
return SharePointSession(site, auth=autoauth)
File "C:\Users\Andrew\AppData\Local\Programs\Python\Python39\lib\site-packages\sharepy\session.py", line 61, in __init__
self.auth.login(self.site)
File "C:\Users\Andrew\AppData\Local\Programs\Python\Python39\lib\site-packages\sharepy\auth\adfs.py", line 27, in login
self._get_token()
File "C:\Users\Andrew\AppData\Local\Programs\Python\Python39\lib\site-packages\sharepy\auth\adfs.py", line 77, in _get_token
raise errors.AuthError('Token request failed. Invalid server response')
sharepy.errors.AuthError: Token request failed. Invalid server response
It should be noted I'm getting O365 from godaddy and the login page is federated? I think is the correct term.
According to the new release of Sharepy, this shouldn't matter.
Has anyone else had this freezing problem happen for them?
How would I authenticate with sharepoint using sharepy given my current situation?
The source of this problem ended up being GoDaddy. As we were federated using GoDaddy as the O365 provider. There was no way to authenticate correctly using sharepy.
The ultimate solution was to defederate away from GoDaddy (pretty easy to do thanks to this guy: Defederation Guide)
The reason we were unable to authenticate was because our provider redirects the login to their own login site. And unfortunately the sharepy builtin method of "auth" wouldn't work with GoDaddy.
I tested this theory before migrating away from GoDaddy. By using a fresh tenant. I also found that when you enable MFA the password/username method of authentication doesn't work.
NOTE: When new tenants are created they utilize a blanket security protocol which forces MFA. Even though MFA is shown as disabled in the Azure AD > Users section. To turn this off you must disable "Security Defaults": portal.azure.com > Azure Active Directory > Properties > "Manage security defaults" (at the bottom of the screen, its a small hyperlink).
A note on MFA and authentication with sharepy. There are methods to leave MFA enabled which work with other sharepoint/python things. I haven't tested them using sharepy yet, but will be turning on MFA and using one of the following methods:
App Password
Sharepoint API client secret
Azure App Registration (Azure App Reg)
Related
Some background: I am working on learning how to convert an app that uses a POP3 connection to use OAuth since Microsoft is dropping support for basic authentication in October. Initially I was using just POP3, but swapped to POP3_SSL after not being able to even enter a username. However, I've run across an issue authenticating with the password
import poplib
email_address = 'redacted#blank.com'
password = 'redacted'
pop3_server = 'outlook.office.com'
server = poplib.POP3(pop3_server)
server.set_debuglevel(1)
pop3_server_welcome_msg = server.getwelcome().decode('utf-8')
print(server.getwelcome().decode('utf-8'))
server.user(user=email_address)
server.pass_(password)
The error:
+OK The Microsoft Exchange POP3 service is ready. [UwBOADcAUABSADAANABDAEEAMAAxADkANgAuAG4AYQBtAHAAcgBkADAANAAuAHAAcgBvAGQALgBvAHUAdABsAG8AbwBrAC4AYwBvAG0A]
*cmd* 'USER redacted#blank.com'
*cmd* 'PASS redacted'
Traceback (most recent call last):
File "testScript.py", line 89, in <module>
server.pass_(password)
File "c:\python27\lib\poplib.py", line 197, in pass_
return self._shortcmd('PASS %s' % pswd)
File "c:\python27\lib\poplib.py", line 160, in _shortcmd
return self._getresp()
File "c:\python27\lib\poplib.py", line 136, in _getresp
raise error_proto(resp)
poplib.error_proto: -ERR Logon failure: unknown user name or bad password.
Copied project from here
Logging into the account via outlook the password works, but doesn't when running the script. If there is a step I have missed, please let me know. Thanks!
As it turns out, I was given the incorrect test email. The one I was using had advanced auth in place. Using an account with only basic auth works fine. Going to close this question.
Setup:
Users are created on On-Prem AD and synced to Azure AD via Azure AD Connect
I have a single-tenant app set up on Azure AD
I created a user (On-Prem, synced to AAD) that can authenticate without MFA (we need to use username-password authentication due to an internal limitation).
Here is the non-interactive authentication code:
import msal
# create a public client app
authority_url = f"https://login.microsoftonline.com/{TENANT_ID}"
msal_app = msal.PublicClientApplication(client_id=CLIENT_ID, authority=authority_url)
# acquire token
token = msal_app.acquire_token_by_username_password(username=USERNAME, password=PASSWORD, scopes=SCOPES)
I'm getting the following error:
Traceback (most recent call last):
File "/./scripts/aad.py", line 8, in <module>
token = msal_app.acquire_token_by_username_password(
File "/usr/local/lib/python3.10/site-packages/msal/application.py", line 1420, in acquire_token_by_username_password
response = _clean_up(self._acquire_token_by_username_password_federated(
File "/usr/local/lib/python3.10/site-packages/msal/application.py", line 1447, in _acquire_token_by_username_password_federated
wstrust_result = wst_send_request(
File "/usr/local/lib/python3.10/site-packages/msal/wstrust_request.py", line 60, in send_request
return parse_response(resp.text)
File "/usr/local/lib/python3.10/site-packages/msal/wstrust_response.py", line 49, in parse_response
raise RuntimeError("WsTrust server returned error in RSTR: %s" % (error or body))
RuntimeError: WsTrust server returned error in RSTR: {'reason': 'MSIS7068: Access denied.', 'code': 'a:FailedAuthentication'}
Searching through Google I found that this can be caused by MFA, but the user is excluded from MFA. I've also verified that there are no Conditional Access policies in place to block the user accessing the app.
Using Interactive auth works as expected. Any ideas on how to get non-interactive auth to work or what might be the issue here?
First, no guesswork! You would need to login to Azure AD with elevated privilege (Security Reader at the least if not Global Administrator).
Go to Enterprise Applications and locate your application by client id.
One you are at the application, go to Sign-in tab/pane.
Review the sign-in activities. You should see the reason authentication failed in overview tab. Look at the Conditional Access tab and you will know if there is any policy that blocked the sign-in.
Take action based on what you identified in sign-in activity.
Okay, I am going to make an educated guess! When you login as non-interactive, you have two authentication choices - ROPC and Client Credential- both requires client_secret to be passed in the request but you have not! Since you are using username and password, it implies that msal is using ROPC and you must include client secret.
I want to automate downloading a zipfile on another organization's sharepoint site that they have shared with my organization, inviting us as a guest using a generic company email address so we can access the files. To gain access, I provide the company email address as username and its associated AD password which authenticates access through our MS 365 organization account.
This works fine manually, but when attempting to do it through shareplum I get a credentials error.
Here is my code:
from shareplum import Site
from shareplum import Office365
from shareplum.site import Version
sharepointUsername = 'elvis.presley#suspiciousminds.org'
sharepointPassword = 'oogabooga123'
sharepointSite = 'https://abc.sharepoint.com/sites/ClientLogin/Shared Documents/Graceland/'
authcookie = Office365(website, username=sharepointUsername,
password=sharepointPassword).GetCookies()
site = Site(sharepointSite, version=Version.v365, authcookie=authcookie)
And here is the error:
Traceback (most recent call last):
File "<string>", line 11, in <module>
File "C:\arcgispro-py3-clone2\lib\site-packages\shareplum\office365.py", line 88, in get_cookies
sectoken = self.get_security_token(self.username, self.password)
File "C:\arcgispro-py3-clone2\lib\site-packages\shareplum\office365.py", line 80, in get_security_token
raise Exception('Error authenticating against Office 365. Error from Office 365:', message[0].text)
Exception: ('Error authenticating against Office 365. Error from Office 365:', 'AADSTS50126: Error validating credentials due to invalid username or password.')
Any clue as why this is not working? I've checked the credentials several times using them to log in manually and it works every time (obviously the example does not have the real username/password)?
You’re not alone, this seems to be a common issue with shareplum over the past 6 months. There’s an open issue on GitHub. The code owner is aware and is having difficulty debugging the issue.
GitHub issue: https://github.com/jasonrollins/shareplum/issues/84
I recommend working closely with the code owner to debug and resolve the issue on GitHub, or using a different library/solution altogether. Another user commented on the issue and referenced a solution that utilizes the requests library to retrieve a file that you may find useful: https://github.com/jasonrollins/shareplum/issues/84#issuecomment-627986466 .
We are currently trying to access a folder of an Office 365 ProPlus tenant using the official OneDrive SDK for Python (https://github.com/OneDrive/onedrive-sdk-python). One of our clients would like to use a OneDrive folder as a way of storing and sharing programmatically generated files, therefore, we would like to provide basic file operations.
We have a working solution for a personal OneDrive account, however, when we try to apply the same approach for their OneDrive, we face an issue during the authentication process.
We asked them to register the application in the Azure AD following the steps in the official documentation. Next, they sent us the redirect URI, client ID and client secret that we included in our script. We are trying to use the following code:
redirect_uri = 'REDIRECT_URI'
client_secret = 'CLIENT_SECRET'
client_id='CLIENT_ID'
discovery_uri = 'https://api.office.com/discovery/'
auth_server_url='https://login.microsoftonline.com/common/oauth2/authorize'
auth_token_url='https://login.microsoftonline.com/common/oauth2/token'
http_provider = onedrivesdk.HttpProvider()
auth_provider = onedrivesdk.AuthProvider(http_provider,
client_id,
auth_server_url=auth_server_url,
auth_token_url=auth_token_url)
auth_url = auth_provider.get_auth_url(redirect_uri)
code = GetAuthCodeServer.get_auth_code(auth_url, redirect_uri)
However, we get the following error message when executing the last line:
Traceback (most recent call last):
File "onedrive-test.py", line 25, in
code = GetAuthCodeServer.get_auth_code(auth_url, redirect_uri)
File "/home/username/.local/lib/python3.6/site-packages/onedrivesdk/helpers/GetAuthCodeServer.py",
line 60, in get_auth_code
s = GetAuthCodeServer((host_address, port), code_acquired, GetAuthCodeRequestHandler)
File "/home/username/.local/lib/python3.6/site-packages/onedrivesdk/helpers/GetAuthCodeServer.py",
line 76, in init
HTTPServer.init(self, server_address, RequestHandlerClass)
File "/usr/lib/python3.6/socketserver.py", line 453, in init
self.server_bind()
File "/usr/lib/python3.6/http/server.py", line 136, in server_bind
socketserver.TCPServer.server_bind(self)
File "/usr/lib/python3.6/socketserver.py", line 467, in server_bind
self.socket.bind(self.server_address)
socket.gaierror: [Errno -2] Name or service not known
We also tried opening the auth_url manually, which took us one step further, but still could not authenticate the application with the following error:
AADSTS50020: User account 'USER ACCOUNT' from identity provider
'live.com' does not exist in tenant 'TENANT NAME' and cannot access
the application 'CLIENT ID' in that tenant. The account needs to be
added as an external user in the tenant first. Sign out and sign in
again with a different Azure Active Directory user account.
We have two questions:
What might casue the first error? This is the comment (see below) that can be found in the readme of the SDK about using the GetAuthCodeServer class. It seems to us that the server cannot be run. Are there any not explicitly defined dependencies that we should be aware of before trying to run the webserver? (We are running the script on Ubuntu 18.10)
If you want to remove some of that manual work, you can
use the helper class GetAuthCodeServer. That helper class spins up a
webserver, so this method cannot be used on all environments.
With respect to the second issue, can you recommend proper material for configuring OneDrive for Business for our use-case? We went through a lot of documentation, but after long hours of research, we still could not find the correct way to fix that issue, especially since we do not have direct acces to the tenant and we cannot easily experiment with things. We would need to give a step-by-step cookbook to our client to set up everything on their side.
Any help would be much appreciated! :)
I'm maintaining a Python application using the official Dropbox API. To ask the users to let my application use their Dropbox account, I use a small script using the DropboxSession class, which is clearly the same as the one we can find on this blog post :
# Include the Dropbox SDK libraries
from dropbox import client, rest, session
# Get your app key and secret from the Dropbox developer website
APP_KEY = '******'
APP_SECRET = '******'
# ACCESS_TYPE should be 'dropbox' or 'app_folder' as configured for your app
ACCESS_TYPE = 'app_folder'
sess = session.DropboxSession(APP_KEY, APP_SECRET, ACCESS_TYPE)
request_token = sess.obtain_request_token()
url = sess.build_authorize_url(request_token)
# Make the user sign in and authorize this token
print "url:", url
print "Please visit this website and press the 'Allow' button, then hit 'Enter' here."
# Python 2/3 compatibility
try:
raw_input()
except NameError:
input()
# This will fail if the user didn't visit the above URL
access_token = sess.obtain_access_token(request_token)
#Print the token for future reference
print access_token
While it's perfectly working with Python 2.7.6, it seems to fail because of Dropbox code in Python 3.4 (the raw_input problem having been dealt with). I get this error :
Traceback (most recent call last):
File "/home/scylardor/.virtualenvs/onitu3/lib/python3.4/site-packages/dropbox/session.py", line 285, in _parse_token
key = params['oauth_token'][0]
KeyError: 'oauth_token'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "get_access_token.py", line 12, in <module>
request_token = sess.obtain_request_token()
File "/home/scylardor/.virtualenvs/onitu3/lib/python3.4/site-packages/dropbox/session.py", line 185, in obtain_request_token
self.request_token = self._parse_token(response.read())
File "/home/scylardor/.virtualenvs/onitu3/lib/python3.4/site-packages/dropbox/session.py", line 287, in _parse_token
raise ValueError("'oauth_token' not found in OAuth request.")
ValueError: 'oauth_token' not found in OAuth request.
Long story short, after having studied the faulty code, it seems that the Dropbox code searches for a string dictionary key, despite the fact that in Python 3, those keys become bytestrings (i.e. it lookups 'oauth_token', which isn't here, instead of b'oauth_token', which is here).
However, even after having fixed the code to see if that's the only issue, no luck, I get another error further in the procedure:
Traceback (most recent call last):
File "get_access_token.py", line 25, in <module>
access_token = sess.obtain_access_token(request_token)
File "/home/scylardor/.virtualenvs/onitu3/lib/python3.4/site-packages/dropbox/session.py", line 214, in obtain_access_token
response = self.rest_client.POST(url, headers=headers, params=params, raw_response=True)
File "/home/scylardor/.virtualenvs/onitu3/lib/python3.4/site-packages/dropbox/rest.py", line 316, in POST
return cls.IMPL.POST(*n, **kw)
File "/home/scylardor/.virtualenvs/onitu3/lib/python3.4/site-packages/dropbox/rest.py", line 254, in POST
post_params=params, headers=headers, raw_response=raw_response)
File "/home/scylardor/.virtualenvs/onitu3/lib/python3.4/site-packages/dropbox/rest.py", line 227, in request
raise ErrorResponse(r, r.read())
dropbox.rest.ErrorResponse: [401] 'Unauthorized'
So the faulty functions are sess.obtain_request_token() and sess.obtain_access_token(request_token). And the Python 2.7 version works fine, but I'd like to keep Python 3 compatibility.
So, does anyone know how one's supposed to make it work in Python 3 ? Could it be deliberately broken in order to make people move on to new procedures ? I could have sworn it was working with Python 3, some time ago.
Thank you for your time if you have an idea :)
edit: It seems the Dropbox SDK just isn't fully Python 3-compatible yet. So, I guess there's nothing else to do than to wait for them to update the SDK.
Try to use version 1.6
$ pip install dropbox==1.6
Better than waiting for the SDK to be compatible, you can use (or contribute to and use) the "community" fork, dropbox-py3 (here on github).
(Those quotes are big quotes. For now it's just me coding this, and just the part I need, but everyone's welcome to help. I think it's mainly identifying the few parts that are missing a ".encode" because it's mixing bytes and strings.)