Django / DRF HTTP_AUTHORIZATION vs AUTHORIZATION in tests - python

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?

Related

How to implement Auth0's Direct Password Change feature using Management API in Django?

I have a Django App, and I am trying to use Auth0 for my Django App's authentication. I have successfully integrated Login and Logout using social-auth-app-django library. But I am facing a lot of hurdles in implementing Auth0's Management API to use direct password change feature in Django? I tried to follow what this Auth0's official documentation's link says to implement Auth0's Management API for direct password change feature, but it is throwing Error Code 500, and I am not understanding what I did wrong.
The link shows the following example to implement Auth0 Management API for firect password change feature in Django:
import http.client
conn = http.client.HTTPSConnection("")
payload = "{\"password\": \"NEW_PASSWORD\",\"connection\": \"CONNECTION_NAME\"}"
headers = { 'content-type': "application/json" }
conn.request("PATCH", "/dev-9fj5kydc.us.auth0.com/api/v2/users/USER_ID", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
And my implementation for the same is:
import http.client
user = self.request.user
NEW_PASSWORD = form.cleaned_data["new_password1"]
CONNECTION_NAME = settings.AUTH0_CONNECTION_NAME
DOMAIN = settings.SOCIAL_AUTH_AUTH0_DOMAIN
USER_ID = user.auth0_id
URL = f"/{DOMAIN}/api/v2/users/{USER_ID}"
conn = http.client.HTTPSConnection("")
payload = f"{{\"password\": \"{NEW_PASSWORD}\",\"connection\": \"{CONNECTION_NAME}\"}}" # Here I am using 'Username-Password-Authentication' as Connection Name
headers = { 'content-type': "application/json" }
conn.request("PATCH", URL, payload, headers)
res = conn.getresponse()
data = res.read()
I have double checked that everything is fine by printing values in console and all variables hold correct values. Can someone help me and tell what wrong I am doing?

APIClient headers for testing

I'm working with django rest_framework and consuming an API that brings a header value to validate the sender. I have the problem when I use APIClient to test the webhook that I made.
#pytest.mark.django_db
def test_change_status_webhook_ok(webhook_client, status_changes):
fixture_signature = (
"51b93156c361bfce14c527ddcb27cc3791e9ea6ede23bc5a56efa3be28e6a54d"
)
url = reverse("webhook_v1:notification")
response = webhook_client.post(
url,
json.dumps(status_changes),
content_type="application/json",
**{"X-Extserv-Signature": fixture_signature}
)
assert response.status_code == 200
The problem is when I tried to get the X-Extserv-Signature from headers.
I tried with:
ret = request.headers.get("X-Extserv-Signature")
this way only works when I receive a request from postman.. but the below form works when I do the request from APIClient and cannot get the value using the same above code.
ret = request.META["X-Extserv-Signature"]
You know how I can set the X-Extserv-Signature key value to headers in APIClient?
From the docs:
A case insensitive, dict-like object that provides access to all HTTP-prefixed headers
request.headers will only contain headers that are HTTP-prefixed, so:
response = webhook_client.post(
url,
json.dumps(status_changes),
content_type="application/json",
**{"HTTP_X_EXTSERV_SIGNATURE": fixture_signature} # <-- Use this
)

how to add authorization headers to bravado-created API client

I am able to create a simple API interface using the requests module that authenticates correctly and receives a response from an API. However, when I attempt to use bravado, to create the client from a swagger file, and manually add an authorization token to the head, it fails with :
bravado.exception.HTTPUnauthorized: 401 Unauthorized: Error(code=u'invalid_credentials', message=u'Missing authorization header',
I believe I am adding the authorization headers correctly.
The code I'm using to create the client is below. As shown, I've tried to add an Authorization token two ways:
in the http_client setup via set_api_key
in the Swagger.from_url(...) step by adding request_headers.
However both options fail.
from bravado.requests_client import RequestsClient
from bravado.client import SwaggerClient
http_client = RequestsClient()
http_client.set_api_key(
'https://api.optimizely.com/v2', 'Bearer <TOKEN>',
param_name='Authorization', param_in='header'
)
headers = {
'Authorization': 'Bearer <TOKEN>',
}
client = SwaggerClient.from_url(
'https://api.optimizely.com/v2/swagger.json',
http_client=http_client,
request_headers=headers
)
My question is, how do I properly add authorization headers to a bravado SwaggerClient?
For reference, a possible solution is to add the _request_options with each request:
from bravado.client import SwaggerClient
headers = {
'Authorization': 'Bearer <YOUR_TOKEN>'
}
requestOptions = {
# === bravado config ===
'headers': headers,
}
client = SwaggerClient.from_url("<SWAGGER_JSON_URL>")
result = client.<ENTITY>.<ACTION>(_request_options=requestOptions).response().result
print(result)
However, a better solution, which I still am unable to get to work, is to have it automatically authenticate with each request.
Try again, fixing the host of the set_api_key line.
from bravado.requests_client import RequestsClient
from bravado.client import SwaggerClient
http_client = RequestsClient()
http_client.set_api_key(
'api.optimizely.com', 'Bearer <TOKEN>',
param_name='api_key', param_in='header'
)
client = SwaggerClient.from_url(
'https://api.optimizely.com/v2/swagger.json',
http_client=http_client,
)
Here you will find documentation about the method : https://github.com/Yelp/bravado/blob/master/README.rst#example-with-header-authentication

oauth1.0 with username and password in 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")

Flask-Security API Token

I have a Flask-Admin app running with Flask-Security and use a token based authentication for API calls. Everything was working correctly. The following method is what returned the token.
def get_token(self):
url = 'http://nginx/login'
headers = {'Content-Type':'application/json'}
data = {'email':os.environ['SCRAPER_USERNAME'],
'password':os.environ['SCRAPER_PASSWORD']}
response = requests.post(url, headers=headers, data=json.dumps(data))
jsonresponse = json.loads(response.text)
self.token = jsonresponse['response']['user']['authentication_token']
I have now added templates to the login and logout pages of Flask-Admin and changed the urls to /admin/login. So I changed the one line from url = 'http://nginx/login' to url = 'http://nginx/admin/login' I thought this was all that was necessary but unfortunately I am now experiencing issues. This method now returns a 400 error when trying to load nginx/admin/login.
Nginx is the server running in a docker container. So it appears creating custom templates has caused the issue. Would anyone know why and how to resolve it?

Categories