Symantec End Point Manager API - Authentication issues - python

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

Related

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 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

Problem when getting 'Authorization' header on test Flask application with FlaskClient

I'm testing my Flask application using FlaskClient, in order to avoid to run a Flask server always when I'm testing my application.
I've created a 'sign_in' view that returns an 'Authorization' header with a encrypted token when the user logs successfully in my front-end.
This view works normally in a normal environment, it returns the 'Authorization' header correctly, however when I'm testing this view, inside the test environment, it does not return the 'Authorization' header. The view returns None in 'Authorization' header.
I've already tried some solutions on the internet, such as to add self.app.config['TESTING'] = True in my test case, but the terminal raises an error 'FlaskClient' object has no attribute 'config' that I've already tried to look for a solution, but without success.
I would like to know what may be happening.
Does anyone know any solution for this question?
I send my code below for analysis.
Thank you in advance.
view.py
#app.route("/sign_in", methods = ["POST"])
def sign_in():
...
username, password = ...
try:
encoded_jwt_token = auth_login(username, password)
except UserDoesNotExistException as error:
return str(error), error.status_code
resp = Response("Returned Token")
resp.headers['Authorization'] = encoded_jwt_token
return resp
test.py
class TestAPIAuthLogin(TestCase):
def setUp(self):
self.app = catalog_app.test_client()
# self.app.config['TESTING'] = True # config does not exist
def test_get_api_auth_login_user_test(self):
username = "test"
password = get_string_in_hash_sha512("test")
authorization = 'Basic ' + get_string_in_base64(username + ":" + password)
headers = {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json',
'Authorization': authorization
}
response = self.app.get('/sign_in', headers=headers)
# it returns None
authorization = response.headers.get("Authorization")
self.assertIsNotNone(authorization)
self.assertNotEqual(authorization, "")
I believe this may be to do with the way HTTP requests process headers, where they capitalise them and add HTTP_ as a prefix. Try changing your header to HTTP_AUTHORIZATION instead of just Authorization, since the test client will not be setting this properly.
I'm sorry guys for this silly question.
Now I've figure the answer out.
The problem was that I was trying to do a GET request in a view that is using a POST method.
I've just replaced the request from
response = self.app.get('/sign_in', headers=headers)
to
response = self.app.post('/sign_in', headers=headers)
and now it started to work.
I will let this question here in case of someone gets the same silly error.
Thank you so much.
If similar issue for DRF clients, You can use,
client = APIClient()
client.credentials(HTTP_AUTHORIZATION='Token {token}'.format(token=token))
Ref: https://www.django-rest-framework.org/api-guide/testing/#credentialskwargs

Requests package and API documentation

I'm having trouble understanding where to add parameters defined by API documentation. Take BeeBole's documentation for example, which specifies that to get an absence by ID, the following request is required:
{
"service": "absence.get",
"id": "absence_id"
}
They provide only one URL in the documentation:
BeeBole is accepting HTTP POST resquests in a json-doc format to the following URL:
https://beebole-apps.com/api/v2
How would this be implemented in the context of Python requests? The following code I've tried returns 404:
import requests
payload = {
"service": "absence.get",
"id": "absence_id"
}
auth = {
"username": "API_token",
"password": "x"
}
url = "https://beebole-apps.com/api/v2"
req = requests.get(url, params=payload, auth=auth).json()
BeeBole is accepting HTTP POST resquests in a json-doc format to the following URL: https://beebole-apps.com/api/v2
The JSON document format here is the part you missed; you need to pass the information as a JSON encoded body of the request. The params argument you used only sets the URL query string (the ?... part in a URL).
Use
import requests
payload = {
"service": "absence.get",
"id": "absence_id"
}
auth = ("API_token", "x")
url = "https://beebole-apps.com/api/v2"
req = requests.get(url, json=payload, auth=auth).json()
The json= part ensures that the payload dictionary is encoded to JSON and sent as a POST body. This also sets the Content-Type header of the request.
I've also updated the API authentication, all that the auth keyword needs here is a tuple of the username and password. See the Basic Authentication section.
You may want to wait with calling .json() on the response; check if the response was successful first:
req = requests.get(url, json=payload, auth=auth)
if not req.ok:
print('Request not OK, status:', req.status_code, req.reason)
if req.content:
print(req.text)
else:
data = req.json()
if data['status'] == 'error':
print('Request error:', data['message'])
This uses the documented error responses.
From the site documentation it would appear that this particular vendor has chosen an unusual API. Most people use different endpoints to implement different operations, but BeeBole appears to implement everything off the one endpoint, and then selects the operation by examining the "service" key in the request data.
Try
response - request.post('https://beebole-apps.com/api/v2',
json={"service": "company.list"},
headers={"authorization": TOKEN)
From the documentation I can't guarantee that will put the request in the right format, but at least if it doesn't work it should give you some clue as to how to proceed. Establishing the correct value of TOKEN is described under "Authorization" in the BeeBole documentation.
It's an unusual way to offer an API, but it seems workable.

Discord API 401 Unauthorized with OAuth

Quick question: I'm trying to use the Discord API to make a backup of all the messages on a server (or a guild, if you use the official term).
So I implemented OAuth without any problems, I have my access token and I can query some endpoints (I tried /users/#me, /users/#me/guilds). Though, most of them don't work. For example, if I query /users/#me/channels (which is supposed to be the DMs) I get a 401 Unauthorized response from the API. It's the same if I gather a guild id from /users/#me/guilds and then try to list the channels in it with /guilds/guild.id/channels.
The really weird thing is that I do have all the scopes required (I think so, I didn't take the RPC ones since I don't think it's required for what I want to do) and I can't figure it out myself... What is also weird is that on the OAuth authorization screen, I have those two things:
It kind of counterdicts itself... :(
Do you have any ideas you'd like to share ?
Thanks!
Note: I'm using Python but I don't think it's related here, since some endpoints do work with the headers and tokens I have...
Here is my "authentication code":
baseUrl = "https://discordapp.com/api"
def authorize():
scopes = [
"guilds",
"email",
"identify",
"messages.read",
"guilds.join",
"gdm.join",
"connections"
]
urlAuthorize = "{}/oauth2/authorize?client_id={}&scope={}&response_type=code".format(baseUrl, clientid, ('+'.join(scopes)))
pyperclip.copy(urlAuthorize)
code = input("Code: ")
return code
def getAccessToken(code):
url = "{}/oauth2/token".format(baseUrl)
params = {
"client_id" : clientid,
"client_secret" : clientsecret,
"redirect_uri" : "http://localhost",
"grant_type":"authorization_code",
"code" : code,
}
req = requests.post(url, params = params)
return json.loads(req.text)
And the code related to an API request:
def getHeaders():
return {
"Authorization" : "{} {}".format("Bearer", config["accessToken"]),
# "user-agent" : "DiscordBackup/0.0.1"
}
def getRequest(endpoint, asJson = True, additional = None):
url = "{}/{}".format(baseUrl, endpoint)
req = requests.get(url, headers = getHeaders())
print()
print(getHeaders())
print(url)
print(req.text)
if asJson:
return json.loads(req.text)
else:
return req.text
def getMe(): # this works
endpoint = "users/#me"
return getRequest(endpoint)
def getMyDMs(): # this gives me a code 401 Unauthorized
endpoint = "/users/#me/channels"
return getRequest(endpoint)
I came across this post when encountering this issue, and to put it bluntly, there's no way to resolve it.
The messages.read permission is for a local RPC server; https://discordapp.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes
However, local RPC servers are in private beta and you must sign up/get accepted to use this.
I wanted to create a DM exporter, but that doesn't look likely now.

Categories