oauth1.0 with username and password in python - python

I am trying to integrate qwikcilver API in my project. They are using oauth1.0 for authentication. I am using requests-oauthlib python lib for oauth1.0.
Here is my code for authentication.
# Using OAuth1Session
oauth = OAuth1Session(client_key, client_secret=client_secret)
fetch_response = oauth.fetch_request_token(request_token_url)
{
"oauth_token": "Z6eEdO8MOmk394WozF5oKyuAv855l4Mlqo7hhlSLik",
"oauth_token_secret": "Kd75W4OQfb2oJTV0vzGzeXftVAwgMnEK9MumzYcM"
}
resource_owner_key = fetch_response.get('oauth_token')
resource_owner_secret = fetch_response.get('oauth_token_secret')
My query is as following,
qwikcilver has username and password. I tried lot to send username and password in code but not working.
How to pass username and password in requests-oauthlib request function?

Check with qwikcilver (whatever that is) if they have provision to generate token and authorize. If so, you can use the token as a part of the header and invoke the APIs. If that is not there, check if they allow 2-legged calls. Such services usually do not allow 2-legged calls for general users however.
For a 3-legged call, you may need a browser to complete Authorization.
In your code, you have invoked Request Token and you are trying to use it to gain access to service. Which will not work. Request Token is just a provisional token which has to be Authorized. Request Tokens cannot be used for such API calls. It will not work. After Authorization, you will need to invoke Access Token API to get your actual token - which can be used to gain access to the services you are authorized to.
In short, this is the process
1) Request Token >>
2) Authorize >>
3) Access Token
This is the flow. A sample in Python
oauth1Session = OAuth1Session(clientKey, clientSecret)
def requestToken(self):
requestTokenResponse = oauth1Session.fetch_request_token(oauth1RequestTokenUrl, realm)
token = requestTokenResponse.get('oauth_token')
secret = requestTokenResponse.get('oauth_token_secret')
return (token, secret)
def authorize(self, token):
authUrl = oauth1Session.authorization_url(oauth1AuthorizeUrl, token)
print (authUrl)
#########
# THIS IS WHERE YOU NEED THE BROWSER.
# You visit authUrl and login with your Username and Password.
# This will complete Authorization
return authUrl
def accessToken(self):
accessTokenResponse = oauth1Session.fetch_access_token(oauth1AccessTokenUrl)
print (accessTokenResponse)
#########
#accessTokenResponse contains your actual token
#
For the browser part - you can try Chromium bindings for Python (there are few who have tried it before - for example this one https://github.com/cztomczak/cefpython). There are other options such as using your default installed browser and other such. Choose whatever works for you.
Once you have that in place - you may programatically visit the URL (authUrl) and once authorized (login, then 'allow') - you may be redirected to a callback (which you specified in case of OAuth1) with the "code" query string. This is the Authorization Code.
Once you have the authorization code, you may close the browser window and invoke the Get Access Token call (fetch_access_token).
Hope this helps !

Im adding an example with a post body. This is a simple example using a request/post with a "Plain Old XML" (POX) pattern:
from requests_oauthlib import OAuth1Session
CONSUMER_KEY = "xxxxxxx"
CONSUMER_SECRET = "xxxxxxx"
ourSession = OAuth1Session(CONSUMER_KEY, client_secret=CONSUMER_SECRET, force_include_body=True)
body= '<?xml version="1.0" encoding="UTF-8"?>' \
'<POXEnvelopeRequest xmlns="http://whateve">' \
'<POXHeader>' \
' <RequestHeaderInfo>' \
. . . .
' </RequestHeaderInfo>' \
'</POXHeader>' \
'</POXEnvelopeRequest>'
clen = str(len(body))
headers = {
'Accept': '*/*',
'Accept-Encoding': 'gzip, deflate, br',
'Host': 'X.Y.com',
'Content-Type': 'application/xml',
'Connection': 'keep-alive',
'Content-Length': clen
}
r = ourSession.post(url, headers=headers, data=body, verify=False)
# DEBUG: Comment out in and out as needed...
print("===================== B E G I N R E S P O N S E =======================\n")
print(r)
print(r.text)
print("===================== E N D of R E S P O N S E =======================\n")

Related

Django / DRF HTTP_AUTHORIZATION vs AUTHORIZATION in tests

I'm using session authentication with Django and DRF
In my tests I need to set the HTTP_AUTHORIZATION header, i.e. using APITestFactory
url = reverse("login")
token = base64.b64encode(b"user:password").decode()
auth_header_str = f"Basic {token}"
self.client.post(url, **{"HTTP_AUTHORIZATION": auth_header_str})
Where as, when using requests it needs AUTHORIZATION, i.e.
token = base64.b64encode(b"user:password").decode()
auth_header_str = f"Basic {token}"
sesh = requests.Session()
r = sesh.post(
"http://localhost:8000/auth/login",
headers={"AUTHORIZATION": auth_header_str},
)
Neither works in both case and they both don't work in each others cases, why is this?

Python requests 401 unauthorized when trying to use CrowdStrike's Event Stream API

I'm trying to import data from CrowdStrike using thier Event-stream API (which I've made sure to enable for the client I use). After authenticating and using the token I get HTTP 401 unauthorized.
client = OAuth2Session(client=BackendApplicationClient(CrowdStrike.get('cid')))
client.fetch_token(token_url=CrowdStrike.get('url_token'), client_secret=CrowdStrike.get('secret'))
response = client.get(CrowdStrike['url_stream']) # 200 OK
# Parse response
j = json.loads(response.text)
url_data_feed = j['resources'][0]['dataFeedURL']
response = client.get(url_data_feed + "&offset=0") # 401 Unauthorized
The last step results an 401 unauthorized- even though the request had an 'Authorization': 'Bearer ' header.
I've even made sure the same bearer is used:
and the token's expired is set to 30 minutes, so it should be vaild.
Any ideas how to fix this?
The following code should work:
resp = requests.get(url_data_feed + "&offset=0",
stream=True,
headers={'Accept': 'application/json',
'Authorization': f'Token {token}'})
This is due to CrowdStrike's authentication requiring the 'Authorization' header to start with 'Token' and not with 'Bearer' (as defaulted by the oauthlib.oauth2 lib).
Also, make sure to include the stream=True as otherwise the program will get stuck.

Python Requests HTTP POST response cookie missing / hiding fields

new to using Python requests lib, and looking for a little help around accessing cookies...
I am unable to get access to all of the fields within a cookie that I get from the following code using the Requests library - similar code from GoLang or Postman all work fine, but for some reason i am missing a few key fields that I need from Python-land. Sample code is as follows:
import requests
# Host base URL
host = 'sampleurl.link/endpoint'
# Username and password for login to API endpoint
credentials = "username=sausage123%40spaniel.org&password=Passw0rd"
ses = requests.Session()
authString = ''
def auth(host):
payload = credentials
headers = {
'Content-Type': "application/x-www-form-urlencoded",
}
ses.post("https://" + host + "/auth", data=payload, headers=headers)
cookies = ses.cookies.get_dict()
print(cookies.items())
authString = "; ".join([str(x)+"="+str(y) for x,y in cookies.items()])
print(authString)
auth(host)
The output is as follows:
[('systemid3', 'eSgRCbaH2EWyBVbRyfBS7xfftYCAqE-BRaon1Uc350pi14qTVgsmDXLrK9TDJvPsKmAzgw==')]
However, from the same API call in GoLang or Postman equiv. i get all of the required fields including path and expires:
systemid3=eSgRCbaH2EWyBVbRyfBS7xfftYCAqE-BRaon1Uc350pi14qTVgsmDXLrK9TDJvPsKmAzgw==; Path=/; Expires=Sat, 21 Sep 2019 09:37:46 GMT
Note that Postman also gives me the same 'Path' and 'Expires' fields etc.
How do i get Requests lib to give me access to all of the fields in the cookie, not just the first 2? Why is it hiding / removing the othe cookie fields?
Thanks in advance!
It's because you're using .items(), it only gets cookie name and value
You can access other parts like this:
for cookie in s.cookies:
print(cookie.name)
print(cookie.value)
print(cookie.expires)
print(cookie.path)

How to make a HTTP Basic Authentication post request where password is generated by TOTP in Python?

The task is to make a HTTP post request to url sending a json string data over, url is protected by HTTP Basic Authentication, I need to provide an Authorization: field in header, and emailAdd is the userid of Basic Authentication, password is generated by TOTP, where digits is 10-digit, time step is 30s, T0 is 0, hash function uses sha512, and shared secret is emailAdd + "ABCD".
My code is like:
import requests, base64, json
from passlib.totp import TOTP
from requests.auth import HTTPBasicAuth
totp = TOTP(key = base64.b32encode(shared_secret.encode()), digits = 10, alg = "sha512")
password = totp.generate().token
r = requests.Session()
#auth = base64.b64encode((''.join(userid) + ':' + ''.join(password)).encode())
r.headers.update({"Content-Type": "application/json"}) #this is task required
#r.headers.update({"Authorization": "Basic " + auth.decode()})
res = r.post(url, json = data, auth = (userid, password))
print(res.status_code)
print(res.content)
But I failed authentication, I think the password should be correct, and there is something wrong with post request, can anyone please tell me what the problem is? Also, I'm in a different time zone from the server, does it make any difference on TOTP generated password? And I'm running python on windows, if that matters.
Thanks

How to request pages from website that uses OpenID?

This question has been asked here before. The accepted answer was probably obvious to both questioner and answerer---but not to me. I have commented on the above question to get more precisions, but there was no response. I also approached the meta Q&A for help on how to bring back questions from their grave, and got no answer either.
The answer to the here above question was:
From the client's perspective, an OpenID login is very similar to any other web-based login. There isn't a defined protocol for the client; it is an ordinary web session that varies based on your OpenID provider. For this reason, I doubt that any such libraries exist. You will probably have to code it yourself.
I know how to log onto a website with Python already, using the Urllib2 module. But that's not enough for me to guess how to authenticate to an OpenID.
I'm actually trying to get my StackOverflow inbox in json format, for which I need to be logged in.
Could someone provide a short intro or a link to a nice tutorial on how to do that?
Well I myself don't know much about OpenID but your post (and the bounty!!) got me interested.
This link tells the exact flow of OpenID authentication sequence (Atleast for v1.0. The new version is 2.0). From what I could make out, the steps would be something like
You fetch the login page of stackoverflow that will also provide an option to login using OpenID (As a form field).
You send ur openID which is actually a form of uri and NOT username/email(If it is Google profile it is your profile ID)
Stackoverflow will then connect to your ID provider (in this case google) and send you a redirect to google login page and another link to where you should redirect later (lets say a)
You can login to the google provided page conventionally (using POST method from Python)
Google provides a cryptographic token (Not pretty sure about this step) in return to your login request
You send the new request to a with this token.
Stackoverflow will contact google with this token. If authenticity established, it will return a session ID
Later requests to STackOverflow should have this session ID
No idea about logging out!!
This link tells about various responses in OpenID and what they mean. So maybe it will come in handy when your code your client.
Links from the wiki page OpenID Explained
EDIT: Using Tamper Data Add on for Firefox, the following sequence of events can be constructed.
User sends a request to the SO login page. On entering the openID in the form field the resulting page sends a 302 redirecting to a google page.
The redirect URL has a lot of OpenID parameters (which are for the google server). One of them is return_to=https://stackoverflow.com/users/authenticate/?s=some_value.
The user is presented with the google login page. On login there are a few 302's which redirect the user around in google realm.
Finally a 302 is received which redirects user to stackoverflow's page specified in 'return_to' earlier
During this entire series of operation a lot of cookie's have been generated which must be stored correctly
On accessing the SO page (which was 302'd by google), the SO server processes your request and in the response header sends a field "Set-Cookie" to set cookies named gauth and usr with a value along with another 302 to stackoverflow.com. This step completes your login
Your client simply stores the cookie usr
You are logged in as long as you remeber to send the Cookie usr with any request to SO.
You can now request your inbox just remeber to send the usr cookie with the request.
I suggest you start coding your python client and study the responses carefully. In most cases it will be a series of 302's with minimal user intervention (except for filling out your Google username and password and allowing the site page).
However to make it easier, you could just login to SO using your browser, copy all the cookie values and make a request using urllib2 with the cookie values set.
Of course in case you log out on the browser, you will have to login again and change the cookie value in your python program.
I know this is close to archeology, digging a post that's two years old, but I just wrote a new enhanced version of the code from the validated answer, so I thought it may be cool to share it here, as this question/answers has been a great help for me to implement that.
So, here's what's different:
it uses the new requests library that is an enhancement over urllib2 ;
it supports authenticating using google's and stackexchange's openid provider.
it is way shorter and simpler to read, though it has less printouts
here's the code:
#!/usr/bin/env python
import sys
import urllib
import requests
from BeautifulSoup import BeautifulSoup
def get_google_auth_session(username, password):
session = requests.Session()
google_accounts_url = 'http://accounts.google.com'
authentication_url = 'https://accounts.google.com/ServiceLoginAuth'
stack_overflow_url = 'http://stackoverflow.com/users/authenticate'
r = session.get(google_accounts_url)
dsh = BeautifulSoup(r.text).findAll(attrs={'name' : 'dsh'})[0].get('value').encode()
auto = r.headers['X-Auto-Login']
follow_up = urllib.unquote(urllib.unquote(auto)).split('continue=')[-1]
galx = r.cookies['GALX']
payload = {'continue' : follow_up,
'followup' : follow_up,
'dsh' : dsh,
'GALX' : galx,
'pstMsg' : 1,
'dnConn' : 'https://accounts.youtube.com',
'checkConnection' : '',
'checkedDomains' : '',
'timeStmp' : '',
'secTok' : '',
'Email' : username,
'Passwd' : password,
'signIn' : 'Sign in',
'PersistentCookie' : 'yes',
'rmShown' : 1}
r = session.post(authentication_url, data=payload)
if r.url != authentication_url: # XXX
print "Logged in"
else:
print "login failed"
sys.exit(1)
payload = {'oauth_version' : '',
'oauth_server' : '',
'openid_username' : '',
'openid_identifier' : ''}
r = session.post(stack_overflow_url, data=payload)
return session
def get_so_auth_session(email, password):
session = requests.Session()
r = session.get('http://stackoverflow.com/users/login')
fkey = BeautifulSoup(r.text).findAll(attrs={'name' : 'fkey'})[0]['value']
payload = {'openid_identifier': 'https://openid.stackexchange.com',
'openid_username': '',
'oauth_version': '',
'oauth_server': '',
'fkey': fkey,
}
r = session.post('http://stackoverflow.com/users/authenticate', allow_redirects=True, data=payload)
fkey = BeautifulSoup(r.text).findAll(attrs={'name' : 'fkey'})[0]['value']
session_name = BeautifulSoup(r.text).findAll(attrs={'name' : 'session'})[0]['value']
payload = {'email': email,
'password': password,
'fkey': fkey,
'session': session_name}
r = session.post('https://openid.stackexchange.com/account/login/submit', data=payload)
# check if url changed for error detection
error = BeautifulSoup(r.text).findAll(attrs={'class' : 'error'})
if len(error) != 0:
print "ERROR:", error[0].text
sys.exit(1)
return session
if __name__ == "__main__":
prov = raw_input('Choose your openid provider [1 for StackOverflow, 2 for Google]: ')
name = raw_input('Enter your OpenID address: ')
pswd = getpass('Enter your password: ')
if '1' in prov:
so = get_so_auth_session(name, pswd)
elif '2' in prov:
so = get_google_auth_session(name, pswd)
else:
print "Error no openid provider given"
r = so.get('http://stackoverflow.com/inbox/genuwine')
print r.json()
the code is also available as a github gist
HTH
This answer sums up what others have said below, especially RedBaron, plus adding a method I used to get to the StackOverflow Inbox using Google Accounts.
Using the Tamper Data developer tool of Firefox and logging on to StackOVerflow, one can see that OpenID works this way:
StackOverflow requests authentication from a given service (here Google), defined in the posted data;
Google Accounts takes over and checks for an already existing cookie as proof of authentication;
If no cookie is found, Google requests authentication and sets a cookie;
Once the cookie is set, StackOverflow acknowledges authentication of the user.
The above sums up the process, which in reality is more complicated, since many redirects and cookie exchanges occur indeed.
Because reproducing the same process programmatically proved somehow difficult (and that might just be my illiteracy), especially trying to hunt down the URLs to call with all locale specifics etc. I opted for loging on to Google Accounts first, getting a well deserved cookie and then login onto Stackoverflow, which would use the cookie for authentication.
This is done simply using the following Python modules: urllib, urllib2, cookielib and BeautifulSoup.
Here is the (simplified) code, it's not perfect, but it does the trick. The extended version can be found on Github.
#!/usr/bin/env python
import urllib
import urllib2
import cookielib
from BeautifulSoup import BeautifulSoup
from getpass import getpass
# Define URLs
google_accounts_url = 'http://accounts.google.com'
authentication_url = 'https://accounts.google.com/ServiceLoginAuth'
stack_overflow_url = 'https://stackoverflow.com/users/authenticate'
genuwine_url = 'https://stackoverflow.com/inbox/genuwine'
# Build opener
jar = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(jar))
def request_url(request):
'''
Requests given URL.
'''
try:
response = opener.open(request)
except:
raise
return response
def authenticate(username='', password=''):
'''
Authenticates to Google Accounts using user-provided username and password,
then authenticates to StackOverflow.
'''
# Build up headers
user_agent = 'Mozilla/5.0 (Ubuntu; X11; Linux i686; rv:8.0) Gecko/20100101 Firefox/8.0'
headers = {'User-Agent' : user_agent}
# Set Data to None
data = None
# Build up URL request with headers and data
request = urllib2.Request(google_accounts_url, data, headers)
response = request_url(request)
# Build up POST data for authentication
html = response.read()
dsh = BeautifulSoup(html).findAll(attrs={'name' : 'dsh'})[0].get('value').encode()
auto = response.headers.getheader('X-Auto-Login')
follow_up = urllib.unquote(urllib.unquote(auto)).split('continue=')[-1]
galx = jar._cookies['accounts.google.com']['/']['GALX'].value
values = {'continue' : follow_up,
'followup' : follow_up,
'dsh' : dsh,
'GALX' : galx,
'pstMsg' : 1,
'dnConn' : 'https://accounts.youtube.com',
'checkConnection' : '',
'checkedDomains' : '',
'timeStmp' : '',
'secTok' : '',
'Email' : username,
'Passwd' : password,
'signIn' : 'Sign in',
'PersistentCookie' : 'yes',
'rmShown' : 1}
data = urllib.urlencode(values)
# Build up URL for authentication
request = urllib2.Request(authentication_url, data, headers)
response = request_url(request)
# Check if logged in
if response.url != request._Request__original:
print '\n Logged in :)\n'
else:
print '\n Log in failed :(\n'
# Build OpenID Data
values = {'oauth_version' : '',
'oauth_server' : '',
'openid_username' : '',
'openid_identifier' : 'https://www.google.com/accounts/o8/id'}
data = urllib.urlencode(values)
# Build up URL for OpenID authetication
request = urllib2.Request(stack_overflow_url, data, headers)
response = request_url(request)
# Retrieve Genuwine
data = None
request = urllib2.Request(genuwine_url, data, headers)
response = request_url(request)
print response.read()
if __name__ == '__main__':
username = raw_input('Enter your Gmail address: ')
password = getpass('Enter your password: ')
authenticate(username, password)
You need to implement cookies on any "login" page, in Python you use cookiejar. For example:
jar = cookielib.CookieJar()
myopener = urllib2.build_opener(urllib2.HTTPCookieProcessor(jar))
#myopener now supports cookies.
....
I made a simple script that logins to stackoverflow.com using Mozilla Firefox cookies. It's not entirely automated, because you need to login manually, but it's all i managed to do.
Scipt is actual for latest versions of FF ( i'm using 8.0.1 ), but you need to get latest sqlite dll, because default one that comes with python 2.7 can't open DB. You can get it here: http://www.sqlite.org/sqlite-dll-win32-x86-3070900.zip
import urllib2
import webbrowser
import cookielib
import os
import sqlite3
import re
from time import sleep
#login in Firefox. Must be default browser. In other cases log in manually
webbrowser.open_new('http://stackoverflow.com/users/login')
#wait for user to log in
sleep(60)
#Process profiles.ini to get path to cookies.sqlite
profile = open(os.path.join(os.environ['APPDATA'],'Mozilla','Firefox','profiles.ini'), 'r').read()
COOKIE_DB = os.path.join(os.environ['APPDATA'],'Mozilla','Firefox','Profiles',re.findall('Profiles/(.*)\n',profile)[0],'cookies.sqlite')
CONTENTS = "host, path, isSecure, expiry, name, value"
#extract cookies for specific host
def get_cookies(host):
cj = cookielib.LWPCookieJar()
con = sqlite3.connect(COOKIE_DB)
cur = con.cursor()
sql = "SELECT {c} FROM moz_cookies WHERE host LIKE '%{h}%'".format(c=CONTENTS, h=host)
cur.execute(sql)
for item in cur.fetchall():
c = cookielib.Cookie(0, item[4], item[5],
None, False,
item[0], item[0].startswith('.'), item[0].startswith('.'),
item[1], False,
item[2],
item[3], item[3]=="",
None, None, {})
cj.set_cookie(c)
return cj
host = 'stackoverflow'
cj = get_cookies(host)
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
response = opener.open('http://stackoverflow.com').read()
# if username in response - Auth successful
if 'Stanislav Golovanov' in response:
print 'Auth successful'

Categories