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
Related
I have to trigger a pipeline in Azure DevOps from a python script. I have already found out that i need a private access token and that part is fine. I can, however, not get the script to work. I am trying something like this:
data = [
{
}
]
http = urllib3.PoolManager()
r = http.request('POST', api_url, headers={'Content-Type': 'application/json-patch+json', "Authorization": private_access_token}, body=data)
print(r.status)
print(r.data)
Its a requirement that i have to use urllib3 because I cant use the requests package
data is empty, because looking at the parameters here https://learn.microsoft.com/en-us/rest/api/azure/devops/pipelines/runs/run%20pipeline?view=azure-devops-rest-6.0. Then i dont need any input data? I just want to trigger a pipeline, nothing else
Error message is not very helpful. I get error message 203.
I solved it by using:
authorization = str(base64.b64encode(bytes(':'+private_access_token, 'ascii')), 'ascii')
data = {}
a = json.dumps(data)
http = urllib3.PoolManager()
r = http.request('POST', api_url, headers = {'Content-Type': 'application/json', 'Authorization': 'Basic '+authorization}, body=a)
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.
I'm trying to use the sandbox from https://fhir.epic.com/ for Backend Services.
I am following this tutorial : https://fhir.epic.com/Documentation?docId=oauth2§ion=BackendOAuth2Guide :
I already register a new app,
created a JWT (using SSL keys)
tested the JWT on https://jwt.io/ : works fine!
But I cannot POST the JWT to the endpoint to obtain the access token. I should send a POST request to this URL: https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token.
I'm using python and this is my code so far:
import json
import requests
from datetime import datetime, timedelta, timezone
from requests.structures import CaseInsensitiveDict
from jwt import (
JWT,
jwk_from_dict,
jwk_from_pem,
)
from jwt.utils import get_int_from_datetime
def main():
instance = JWT()
message = {
# Client ID for non-production
'iss': '990573e-13e3-143b-8b03-4fbb577b660',
'sub': '990573e-13e3-143b-8b03-4fbb577b660',
'aud': 'https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token',
'jti': 'f9eaafba-2e49-11ea-8880-5ce0c5aee679',
'iat': get_int_from_datetime(datetime.now(timezone.utc)),
'exp': get_int_from_datetime(datetime.now(timezone.utc) + timedelta(hours=1)),
}
# Load a RSA key from a PEM file.
with open('/home/user/ssl/privatekey.pem', 'rb') as fh:
signing_key = jwk_from_pem(fh.read())
compact_jws = instance.encode(message, signing_key, alg='RS384')
print(compact_jws)
headers = CaseInsensitiveDict()
headers['Content-Type'] = 'application/x-www-form-urlencoded'
data = {
'grant_type': 'client_credentials',
'client_assertion_type': 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
'client_assertion': compact_jws
}
x = requests.post('https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token', headers=headers, data=data)
print(x.text)
But I always get a 400 error:
{
"error": "invalid_client",
"error_description": null
}
Is the URL correct? How can I get an Access Token to play with the Sandbox?
'exp': get_int_from_datetime(datetime.now(timezone.utc) + timedelta(hours=1)),
At first glance, this appears to be your issue. Epic requires that exp be no more than 5 minutes in the future.
Couple of pieces of advice, beyond that:
Use a library available from jwt.io
Jwt.io also has a debugger where you can paste in your JWT to verify it is valid
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)
The following is my code:
import requests, json
proxyDict = {
"http": "<proxy>",
}
base_url = "https://<host_IP>/sepm/api/v1/identity/authenticate"
# if output is required in JSON format
json_format = True
payload = {
"username" : "<username_here>",
"password" : "<password_here>",
"domain" : ""
}
headers = {
"Content-Type" : "application/json"
}
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += 'HIGH:!DH:!aNULL' # necessary
r = requests.Session() # Start session in order to store the SessionID Cookie
print json.dumps(payload)
r = requests.post(base_url, proxies=proxyDict, verify=False, headers=headers, data=json.dumps(payload))
strings = r.text
print strings
The SSL certificate has some errors, and I am hence using verify=False and DEFAULT_CIPHERS += 'HIGH:!DH:!aNULL'
The above code is inline with the documentation provided, but the server is refusing my auth request, with the following error:
{"errorCode":"400","errorMessage":"Invalid Username or Password"}
Before you jump the gun, I checked and rechecked my credentials, and then checked a couple of more times. my credentials are correct
Is there an error in what I am doing?
Additional info: SEPM Version: {"version":"12.1.6168.6000"}
Late to this party, but I was having the same issue with almost the although going about it a bit differently. SO, what my issue ended up being was the special characters in my password. The rest method that handles authentication on the Symantec manager side of things doesn't know how to handle certain special characters so it returns a 400 syntax error. Trying pulling special characters from you password, and keep it under 15 characters.
Good luck.
You might want to try putting the below line near the top of your code:
urllib3.disable_warnings()
And ignore the SSL authentication