converting from python requests method of http auth to aiohttp.BasicAuth - python-requests

I have a working HTTP post request:
`requests.post('http://' + str(ip_address) + addrsuffix, auth=HTTPDigestAuth(username, password), data='payload')`
I'm trying to convert this request to use to asyncio, but using aiohttp I get unauthorised 401 status as a reply.
This is what I tried. I was expecting this to just work, using the BasicAuth username and password method.
async def post_request(session, ip, username, password, data):
digest_auth = aiohttp.BasicAuth(username, password)
url = f'http://{ip}/addrsuffix/'
headers = {CONTENT_TYPE: 'application/json'}
try:
print(f'{username}, {password}, {data}, {digest_auth}')
async with session.post(url, auth=digest_auth, headers=headers, json=data) as resp:
if resp.status == 200:
print(f'Successful post request to {ip}')
else:
print(f'Error {resp.status} for post request to {ip}')
except Exception as e:
print(f'Error: {e} for post request to {ip}')
when I look at how the original python requests method encodes the auth data, I get:
<requests.auth.HTTPDigestAuth object at 0x<a_hex_string> >
but the new aiohttp.BasicAuth method produces:
BasicAuth(login='myusername', password='mypass', encoding='latin1')
It seems to me to be the way it is presenting the credentials as "login" (but I might be wrong).
Can I please get guidance on how to achieve the same auth method as the requests.auth produces?
I've tried to read aiohttp's documentation on BasicAuth but find it hard to comprehend.

Happily answering my own dumb question: aiohttp doesn't support Digest Authentication.
So I stumbled on httpx, which seems to work great for this purpose.

Related

LinkedIn API metrics

#linkedin
I am trying in python to get the metrics (likes, shares, comments, etc) of my company page.
We registered the API which includes Marketing Developer Platform.
I understand, I need Members authentication and I set up Oauth 2.0 settings.
I've created the access_token for the permissions (among them is r_organization_social - which I need to collect data).
What is confusing for me, how to use this token.
Is it enough to use it together with header in my request?
response = requests.get('https://api.linkedin.com/v2/posts', headers = headers)
I've created the header like this:
headers = {
'Authorization': f'Bearer {access_token}',
'cache-control': 'no-cache',
'X-Restli-Protocol-Version': '2.0.0'
}
I tried that and I am getting an error that token is Invalid, even though it is live and active for the next 11 months.
I also tried many things where I would first send request for authenticate my request and then manually copy the response to get the new access token.
That access token never worked - was invalid.
Even if it works, looks like that wouldn't be acceptable solution...
Can you please help with this?
Thanks
The following is working for me.
I used this format of the header:
headers = {
'X-Restli-Protocol-Version': '2.0.0',
'Authorization': 'Bearer '+ access_token }
payload ={}
And the request looks like this (instead of posts I use ugcPosts):
requests.request("GET",'https://api.linkedin.com/v2/ugcPosts?q=authors&authors=List('+urnLiOrganizationEncode + ')&count=100', headers=headers,data=payload)

Encoded / Encrypted body before verifying a Pact

A server I need to integrate with returns its answers encoded as a JWT. Worse, the response body actually is a json, of the form:
{d: token} with token = JWT.encode({id: 123, field: "John", etc.})
I'd like to use a pact verification on the content of the decoded token. I know I can easily have a pact verifying that I get back a {d: string}, I can't do an exact match on the string (as the JWT contains some varying IDs). What I want is the following, which presumes the addition of a new Pact.JWT functionality.
my_provider.
upon_receiving('my request')
.with(method: :post,
path: '/order',
headers: {'Content-Type' => 'application/json'}
).will_respond_with(
status: 200,
headers: {'Content-Type' => 'application/json; charset=utf-8'},
body: {
d: Pact::JWT( {
id: Pact.like(123),
field: Pact.term(generate: "John", matcher: /J.*/
},signing_key,algo
)
})
Short of adding this Pact::JWT, is there a way to achive this kind of result?
I am already using the pact proxy to run my verification. I know you can modify the request before sending it for verification (How do I verify pacts against an API that requires an auth token?). Can you modify the request once you receive it from the proxy server?
If that's the case, I can plan for the following work around:
a switch in my actual code to sometimes expect the answers decoded instead of in the JWT
run my tests once with the swich off (normal code behaviour, mocks returns JWT data encoded.
run my tests a second time with the swich off (code expect data already decoded, mocks return decoded data.)
use the contract json from this second run
hook into the proxy:verify task to decode the JWT on the fly, and use the existing pact mechanisms for verification. (Step that I do not know how to do).
My code is in ruby. I do not have access to the provider.
Any suggestions appreciated! Thanks
You can modify the request or response by using (another) proxy app.
class ProxyApp
def initialize real_provider_app
#real_provider_app = real_provider_app
end
def call env
response = #real_provider_app.call(env)
# modify response here
response
end
end
Pact.service_provider "My Service Provider" do
app { ProxyApp.new(RealApp) }
end
Pact as a tool, I don't expect it to give this behavior out of the box.
In my opinion, the best is,
Do not change source code only for tests
Make sure your tests verifies encoded json only (generate encoded expected json in test & verify that with actual)

Can't access FireBase Database via HTTP/REST error 403 Forbidden

Swift + Vapor framework for server + Xcode 8.1
I am trying to read Firebase Realtime Database making HTTP requests to my DB, but I get permission denied.
These are the steps:
1. create JWT sign it with secret key downloaded from "console.developers.google.com"
2. send POST request to OAuth2 server and get access token
3. send GET request to firebase database with access token received from OAuth2 server.
I get "Permission denied", HTTP/1.1 403 Forbidden
// the header of the JSON Web Token (first part of the JWT)
let headerJWT = ["alg":"RS256","typ":"JWT"]
// the claim set of the JSON Web Token
let jwtClaimSet =
["iss":"firebase-adminsdk-kxx5h#fir-30c9e.iam.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/firebase.database", //is this the correct API to access firebase database?
"aud":"https://www.googleapis.com/oauth2/v4/token",
"exp": expDate,
"iat": iatDate]
drop.get("access") { request in
var accesstoken = "ya29.ElqhA-....XXXX"
let responseFirebase = try drop.client.get("https://fir- 30c9e.firebaseio.com/data/Users.json",
headers: ["Authorization":"Bearer \(accesstoken)"],
query: [:])
print("FirebaseResponse_is \(responseFirebase)")
return "success"
}
TLDR; Try placing auth=<TOKEN> in your query string instead of using the authorization header.
The Firebase documentation is unclear on how this works. According to the documentation, there are three methods that should work.
auth=<TOKEN> in query string (link)
access_token=<TOKEN> in query string (link)
Authorization: Bearer <TOKEN> in request header (link)
I'm not convinced that all three methods do actually work however. I'm using method 1 in my application, so I know that one works for sure.
The scope key was missing value https://www.googleapis.com/auth/userinfo.email
let jwtClaimSet =
["iss":"firebase-adminsdk-kxx5h#fir-30c9e.iam.gserviceaccount.com",
"scope": "https://www.googleapis.com/auth/firebase.database
https://www.googleapis.com/auth/userinfo.email",
"aud":"https://www.googleapis.com/oauth2/v4/token",
"exp": expDate,
"iat": iatDate]
I found the answer browsing google groups here
headers: ["Authorization":"Authorization: Bearer \(accesstoken)"],
should be
headers: ["Authorization":"Bearer \(accesstoken)"],

400 (Bad Request) when requesting GA API

I got a 400 Bad Request when trying to access Google Auth. I am using the demo code in this article:
https://developers.google.com/analytics/solutions/articles/hello-analytics-api
The address I am requesting is:
https://accounts.google.com/o/oauth2/auth?client_id=875938******.apps.googleusercontent.com&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fanalytics.readonly&immediate=true&include_granted_scopes=true&proxy=oauth2relay452650337&redirect_uri=postmessage&origin=http%3A%2F%2Flocalhost%3A8080&response_type=token&state=895891795%7C0.1215960807&authuser=0
I have successfully created my own ClientId and Keys.
Is there anything I need to take care of?
Thanks,
There are several things wrong with your request. First the scope, second the respons_type. I'm not sure where on the page you linked that you found that example. You should really try and find a library for what ever language you are using it will make it easer. But if you want to know the exact URLs you should be posting they should look something like this.
The initial URI to request that the user give you access to there account should look like this In this case the scope notice my scope is different then yours and I'm requesting a code:
https://accounts.google.com/o/oauth2/auth?client_id={clientid}.apps.googleusercontent.com&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/analytics.readonly&response_type=code
Once they say yes you take the authentication Code you got from the above request and Post it back to request an access_token and a refresh_token
https://accounts.google.com/o/oauth2/token
code=4/X9lG6uWd8-MMJPElWggHZRzyFKtp.QubAT_P-GEwePvB8fYmgkJzntDnaiAI&client_id={ClientId}.apps.googleusercontent.com&client_secret={ClientSecret}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code
this is the response:
{
"access_token" : "ya29.1.AADtN_VSBMC2Ga2lhxsTKjVQ_ROco8VbD6h01aj4PcKHLm6qvHbNtn-_BIzXMw",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "1/J-3zPA8XR1o_cXebV9sDKn_f5MTqaFhKFxH-3PUPiJ4"
}
The accesstoken you get from the above request is what you will be using to make requests to the service. After one hour your access token will have expired you will need to request a new access token you take the refreshtoken that you got above and post it to :
https://accounts.google.com/o/oauth2/token
client_id={ClientId}.apps.googleusercontent.com&client_secret={ClientSecret}&refresh_token=1/ffYmfI0sjR54Ft9oupubLzrJhD1hZS5tWQcyAvNECCA&grant_type=refresh_token
This is the response:
{
"access_token" : "ya29.1.AADtN_XK16As2ZHlScqOxGtntIlevNcasMSPwGiE3pe5ANZfrmJTcsI3ZtAjv4sDrPDRnQ",
"token_type" : "Bearer",
"expires_in" : 3600
}
Hope this helps.

PL/SQL OpenID+OAuth Implementation - 400 - Bad Request

I am trying to implement (OpenId+OAuth) hybrid protocol using PL/SQL.
I have setup OpenID Authentication successfully with google for my site http://example.com where the user is directed to google accounts for authentication. After successful authentication, the user is redirected back to example.com with OAuthRequestToken attached.
I am then trying to exchange this token with OAuthAccessToken to access various google sevices.
The OAutheRequestToken that I get after hybrid(OpenID+OAuth) authentication is as follows:
oauth_token = 4/AR17dDMb4xHG3L4WFYLIzkhCj0c7
The oauth_base_string I get is as follows:
oauth_base_string = GET&https%3A%2F%2Fwww.google.com%2Faccounts%2FOAuthGetAccessToken&oauth_consumer_key%3Dexample.com%26oauth_nonce%3D56575A5754587057576E6C77576B78695757354F%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1308046070%26oauth_version%3D1.0%26oauth_token%3D4%2FAR17dDMb4xHG3L4WFYLIzkhCj0c7
I then place a request to exchange this oauth_token(OAuthRequestToken) with OAuthAccessToken in the query string itself as :
https://www.google.com/accounts/OAuthGetAccessToken?oauth_consumer_key=example.com&oauth_token=4/AR17dDMb4xHG3L4WFYLIzkhCj0c7&oauth_signature_method=HMAC-SHA1&oauth_signature=RpqSLGp5nIGvL8W4vmC8inUfBFQ%3D&oauth_timestamp=1308046070&oauth_nonce=56575A5754587057576E6C77576B78695757354F&oauth_version=1.0
This results in 400 - Bad Request.
I have tried searching for something similar but still no luck.
This Post from Stack Overflow deals with a similar issue. It says
...% escaping can be an issue
which is a bit confusing.
Do we have to urlencode oauth_signature param twice in the request?
I am using the following code to generate oauth_signature:
oauth_sig_mac := DBMS_CRYPTO.mac (UTL_I18N.string_to_raw
(oauth_base_string,
'AL32UTF8'),DBMS_CRYPTO.hmac_sh1,
UTL_I18N.string_to_raw (oauth_key,
'AL32UTF8'));
oauth_signature := UTL_RAW.cast_to_varchar2(UTL_ENCODE.base64_encode
(oauth_sig_mac));
Here:
oauth_key := urlencode('oauth-consumer-secret-key') || '&';
Any help is greatly appreciated.
I recommend using https://runscope.com to test your api. Its great.
I make my calls to the Zero api using oauth 1.0, so I'm not sure if its just the endpoint that's different but a couple things you could check are:
Encoding the oauth token you recieve from the previous request so that, that '/' is ASCII encoded.
And, test your api through runscope to check your timestamp if its to old or to new this will throw a bad request.
P.s a bad request is a better error than the 401 anauthorised so your almost there

Resources