HTTP Authentication headers with no "realm" - python

The following code works but gives no output even though there is a file instance lying behind response
import urllib2
from ntlm import HTTPNtlmAuthHandler
user = 'id'
password = "Password"
url = "http://abc.def.ghij:3080"
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None, url, user, password)
# create the NTLM authentication handler
auth_NTLM = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(passman)
# create and install the opener
opener = urllib2.build_opener(auth_NTLM)
urllib2.install_opener(opener)
# retrieve the result
response = urllib2.urlopen("http://abc.def.ghij:3080")
print response.read()
print response.headers
header response:
Cache-Control: private
Content-Length: 0
Location: /index.epx
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.19
Persistent-Auth: true
X-Powered-By: ASP.NET
Date: Thu, 04 Jul 2013 15:30:03 GMT
Connection: close
but print response.read doesnt give any content :O

WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
The problem is that your webserver is requesting NTLM authentication, so it wont accept BasicAuth. Use NTML authentication while sending request or change your webserver config to allow Basic authentication.
Dont use BasicAuth because it sends user/pwd in plaintext over the network. Minimum safe is DigestAuth or NTLM or GSSNegotiate auth.

Related

session cookie not being sent back to server on a per-request basis

I'm trying to implement an authentication system, part of which involves passing around a session cookie to allow the server to verify the user's identity on a per-request basis; however, when registering under a test-case and attempting to access an authenticated endpoint, despite the cookie being set in the test's local cookiejar, it does not appear in the request headers to the server.
The server creates the cookie here, by only setting the expiration date.
headers={
"set-cookie": [{
"name": "__session",
"value": user_obj.serialize_session(),
"expires": cookie_expiry(user_obj.expires_at()),
}]
}
And the test-case is very simple
session = requests.Session()
def register(username, password):
return session.post(
f"{HOST}/api/auth/register",
...
)
def create_invoice(education, desc, budget, deadline, files):
return session.post(
f"{HOST}/api/invoice/create",
...
)
username, password = ...
account = register(username, password)
req = create_invoice(
...
)
# {"status": "error", "reason": "you must be authenticated to use this endpoint"}
On the client-side, the cookie appears to be valid on the register response:
'set-cookie': '__session="..."; expires=Fri, 22-Apr-2022 02:47:46 GMT'
But, the request from the server-side appears without any Cookie header:
Host: www.example.local:8443
User-Agent: python-requests/2.27.1
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 112
Content-Type: application/json
I've looked everywhere in terms of playing around with the Domain and HttpOnly attributes, but nothing appears to work. Is there a certain reason why the requests session isn't putting the session cookie in the request?

What HTTP response codes are retried by python Requests

What are the list of HTTP response status codes retried by default and how many times, by the Python Requests. How can I change the number of retries? I couldn't find any documentation for it.
I tried below code and there were two retries on 401 status code.
import requests
from http.client import HTTPConnection
from requests.auth import HTTPDigestAuth
HTTPConnection.debuglevel = 1
requests.adapters.DEFAULT_RETRIES = 5
def test():
data = 'testdata'
username = 'testuser'
password = 'test'
url='https://example.com:443/captionen_0001.vtt'
try:
response = requests.put(url, auth=HTTPDigestAuth(username,password), data=data, verify=False)
except Exception as e:
print('error'+str(e))
test()
warnings.warn(
send: b'PUT /channel_captionen_0001.vtt HTTP/1.1\r\nHost: example.com\r\nUser-Agent: python-requests/2.24.0\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nConnection: keep-alive\r\nContent-Length: 8\r\n\r\n'
send: b'testdata'
reply: 'HTTP/1.1 401 Authorization Required\r\n'
header: Date: Sat, 05 Feb 2022 07:50:25 GMT
header: WWW-Authenticate: Digest realm="WebDAV", nonce="tE/JnkDX845db3", algorithm=MD5, qop="auth"
warnings.warn(
send: b'PUT /channel_captionen_0001.vtt HTTP/1.1\r\nHost: example.com\r\nUser-Agent: python-requests/2.24.0\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nConnection: keep-alive\r\nContent-Length: 8\r\nAuthorization: Digest username="testuser", realm="WebDAV", nonce="tE/JnkDX845db3", uri="/channel_captionen_0001.vtt", response="1c3299c716797e8f36528f6e6dbaeb50", algorithm="MD5", qop="auth", nc=00000001, cnonce="dd0835ef485c6b71"\r\n\r\n'
send: b'testdata'
reply: 'HTTP/1.1 401 Authorization Required\r\n'
header: Date: Sat, 05 Feb 2022 07:50:25 GMT
header: WWW-Authenticate: Digest realm="WebDAV", nonce="/vXKnkDXBQc098a4", algorithm=MD5, qop="auth
It's not obviously to find. You have to know requests is not the package that manage the connection, urllib3 does.
In the source code of HTTPAdapter (use it when you want more control on requests), the docstring on max_retries parameter said:
If you need granular control over the conditions under which we retry a request, import urllib3's Retry class and pass that instead
Now you can refer to the documentation of urllib3 for Retry class.
Read especially status_forcelist parameter and RETRY_AFTER_STATUS_CODES (default: frozenset({413, 429, 503}))
Update
import requests
import urllib3
my_code_list = [401, 403, ...]
s = requests.Session()
r = urllib3.util.Retry(status_forcelist=my_code_list)
a = requests.adapters.HTTPAdapter(max_retries=r)
s.mount('http://', a)

Azure POST login.microsoftonline.com/oauty2/token fails on AADSTS900144

I need to automate connecting to logs analytics on Azure. Before I can do that, I need to get an access token.
With different docs and https://www.youtube.com/watch?v=ujzrq8Fg9Gc, I am trying to set that up.
TRY1
My first try was using SoapUI to send a POST request to:
https://login.microsoftonline.com/MY TENANT ID/oauth2/token
?grant_type=client_credentials
&client_id=MY CLIENT ID
&redirect_uri=MY URL
&resource=https%3A%2F%2Fwestus2.api.loganalytics.io
&client_secret=MY CLIENT SECRET
With header:
Content-Type: application/x-www-form-urlencoded
I always get this response:
HTTP/1.1 400 Bad Request
Cache-Control: no-cache, no-store
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
x-ms-request-id: SOMETHING
P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
Set-Cookie: fpc=SOMETHING; expires=Mon, 05-Aug-2019 13:14:50 GMT; path=/; secure; HttpOnly
Set-Cookie: x-ms-gateway-slice=prod; path=/; secure; HttpOnly
Set-Cookie: stsservicecookie=ests; path=/; secure; HttpOnly
Date: Sat, 06 Jul 2019 13:14:49 GMT
Content-Length: 437
{
"error":"invalid_request",
"error_description":"AADSTS900144: The request body must contain
the following parameter: 'grant_type'.\r\n
Trace ID: SOMETHING\r\n
Correlation ID: SOMETHING\r\n
Timestamp: 2019-07-06 13:14:50Z",
"error_codes":[900144],
"timestamp":"2019-07-06 13:14:50Z",
"trace_id":"SOMETHING",
"correlation_id":"SOMETHING"
}
TRY 2
I wrote it in Python using import requests, like so:
import os,sys
import requests
Azure_client_id = 'MY CLIENT ID'
Azure_redirect_uri = 'MY URL'
Azure_client_secret = 'CLIENT SECRET'
Azure_tenant_id = 'TENANT ID'
Azure_resource = 'https://westus2.api.loganalytics.io'
###############################################################################
token_url = 'https://login.microsoftonline.com/' + Azure_tenant_id + '/oauth2/token'
token_headers = {
'Content-type': 'application/x-www-form-urlencoded',
}
token_params = {
'grant_type': 'client_credentials',
'client_id': Azure_client_id,
'redirect_uri': Azure_redirect_uri,
'resource': Azure_resource,
'client_secret': Azure_client_secret,
}
token_response = requests.post(token_url, headers=token_headers, params=token_params)
# This is to see what was sent
print(token_response.url + "\n\n")
# get the response and print it
token_result = ''
for chunk in token_response.iter_content(chunk_size=128):
token_result = token_result + str(chunk)
print(token_result.replace("\\n","\n"))
The URL that was sent is this (formatted for readability):
https://login.microsoftonline.com/MY TENANT ID/oauth2/token
?grant_type=client_credentials
&client_id=MY CLIENT ID
&redirect_uri=https%3A%2F%2FMY URL
&resource=https%3A%2F%2Fwestus2.api.loganalytics.io
&client_secret=MY SECRET URL ENCODED
The response I get is this (reformatted for readability):
b'{"error":"invalid_request",
"error_description":"AADSTS900144: The request body must contain
the following parameter: \'grant_type'b"'.\\r\
Trace ID: SOMETHING\\r\
Correlation ID: SOMETHING\\r\
Timestamp: 2019-"b'07-06 13:49:59Z",
"error_codes":[900144],
"timestamp":"2019-07-06 13:49:59Z",
"trace_id":"SOMETHING",
"co'b'rrelation_id":"SOMETHING"}''
At least I get the same error (!). Since my requests clearly include a "grant_type" parameter, my guess is that there is either something wrong with the encoding (which is done by SoapUI and Python's requests), something wrong with my URL, or I am not using the proper IDs.
Is there a way in Azure to validate that my client secret is valid? Once created, it cannot be read anymore. And someone else created this key so I cannot assume what he gave me is ok.
Any comment, hints, pointing out blatant mistakes on my part are appreciated.
Change
token_response = requests.post(token_url, headers=token_headers, params=token_params)
to
token_response = requests.post(token_url, data=token_params)
You don't need to specify the Content-type header, it's inferred from your payload (dictionary, so x-www-form-urlencoded), also data is what you want (payload), not params (URL parameters).
Your request should look like this on the wire -
POST /TENANT_ID/oauth2/token HTTP/1.1
Host: localhost:9000
User-Agent: python-requests/2.22.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 151
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=MY+CLIENT+ID
&redirect_uri=MY+URL
&resource=https%3A%2F%2Fwestus2.api.loganalytics.io
&client_secret=CLIENT+SECRET
Everything is in the body where it should be for x-www-form-urlencoded.
More on x-www-form-urlencoded here -
https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST#Example

Python. Cannot make a request to simple site api. Flask and requests

I am trying to create simple API for my site. I created the route with flask:
#api.route('/api/rate&message_id=<message_id>&performer=<performer_login>', methods=['POST'])
def api_rate_msg(message_id, performer_login):
print("RATE API ", message_id, ' ', performer_id)
return 400
print(...) function don't execute...
I use flask-socketio to communicate between client and server.
I send json from client and process it with:
#socket.on('rate')
def handle_rate(data):
print(data)
payload = {'message_id':data['message_id'], 'performer':data['performer']}
r = requests.post('/api/rate', params=payload)
print (r.status_code)
Note, that data variable is sending from client and is correct(I've checked it).
print(r.status_code) don't exec too...
Where I'm wrong? Please, sorry for my bad english :(
This api function must increase rate of message, which stored in mongodb, if interesting.
Don't put &message_id=<message_id>&performer=<performer_login> in your route string. Instead, get these arguments from request.args.
Try it:
from flask import request
...
#api.route('/api/rate', methods=['POST'])
def api_rate_msg():
print(request.args)
return ''
I've tested it with httpie:
$ http -v POST :5000/api/rate message_id==123 performer_login==foo
POST /api/rate?message_id=123&performer_login=foo HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 0
Host: localhost:5000
User-Agent: HTTPie/0.9.8
HTTP/1.0 200 OK
Content-Length: 0
Content-Type: text/html; charset=utf-8
Date: Sun, 02 Apr 2017 13:54:40 GMT
Server: Werkzeug/0.11.11 Python/2.7.13
And from flask's log:
ImmutableMultiDict([('message_id', u'123'), ('performer_login', u'foo')])
127.0.0.1 - - [02/Apr/2017 22:54:40] "POST /api/rate?message_id=123&performer_login=foo HTTP/1.1" 200 -
Remove the below part from your api route
&message_id=<message_id>&performer=<performer_login
This is not required in POST request. It helps in GET requests. API call in request is not matching the route definition and therefore you have the current problem

Problems to authenticate correctly with pysimplesoap

I'm trying to use pysimplesoap to communicate with the Websitepanel SOAP-API.
The WebsitePanel API Introduction says:
For interacting with WebsitePanel API you should use Basic Authentication. WebsitePanel recognizes “Authorization” header with the user credentials provided in the following format: username:password
My first try was the following:
client = SoapClient(wsdl=endpoint_url, trace=True)
client['Authorization'] = "%s:%s" % (username, password)
which returns a 401 "Unauthorized".
Second try was:
client = SoapClient(wsdl=endpoint_url, trace=True)
client['wsse:Security'] = {
'wsse:UsernameToken': {
'wsse:Username': username,
'wsse:Password': password,
}
}
which works as expected but returns the following:
status: 500
content-length: 924
x-aspnet-version: 4.0.30319
x-powered-by: ASP.NET
server: Microsoft-IIS/7.5
cache-control: private
date: Tue, 12 Feb 2013 14:23:56 GMT
content-type: text/xml; charset=utf-8
And
pysimplesoap.client.SoapFault: q0:Security: SOAP response should be signed.
Why does client['Authorization'] not work and what is meant by the Response should be signed error message?
Thanks in advance.
I figured it out: To authenticate correctly with pysimplesoap you have to call
client = SoapClient(wsdl=u, trace=True,
http_headers={'Authorization': 'Basic %s' % encoded})
with encodedbeeing the base64-encoded string username:password

Categories