0

A server listens packet and we send http GET request packet to this listener.If we use auth header with username/pass server does not accept connection and it fails.Is there any way to parse this auth header info (username/pass) on listener ? Because we want to perform authentication based on user/pass comparison

NOTE : Without auth header in GET packet http listener accept connection and it works fine

HTTP PACKET LISTENER

import socket

serverSocket = socket(AF_INET, SOCK_STREAM)
serverPort = 8080
serverSocket.bind(("127.0.0.1", serverPort))
serverSocket.listen(1)

while True:
    print('Ready to serve...')
    try :
         connectionSocket, addr = serverSocket.accept()
    except :
        print (f"Socket error occured for 127.0.0.1 {serverPort} ")

HTTP CLIENT

import requests
from requests.auth import HTTPBasicAuth

r = requests.get('http://127.0.0.1:8080',auth = HTTPBasicAuth('user', 'pass'))

Thank you for your helps !

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
ElitNows
  • 3
  • 2
  • See here: https://stackoverflow.com/questions/2929532/http-basic-authentication-using-sockets-in-python – floatingpurr Nov 11 '21 at 09:54
  • @floatingpurr but at this example it just sends packet...does not confirm username/password. In my case , my listener program already receives packet from client my question is how can i parse auth header and confirm authentication on packet listener – ElitNows Nov 11 '21 at 10:16
  • 1
    You have to implement a proper HTTP server, i.e. a server which understands the HTTP protocol instead of just a TCP listener as you have know. Then you need to extract the credentials from the Authorization header and check against whatever authentication backend you have. The question as it stands now as too far away from this and thus too broad. It is like having a steering wheel and asking how to build a car around this. – Steffen Ullrich Nov 11 '21 at 11:07
  • I'm gonna post an example / PoC. – floatingpurr Nov 11 '21 at 11:46
  • @floatingpurr thanks for your reply, yeah i knew that :) i need to build proper http server flasjk/django to process http packet and headers.I just wonder maybe there is a way to parse this information by using requests module or socket module.That's why i've asked this question.For now it's clear for me i will use another application data to share username/pass information so that can parse them with regex Thanks again for your explanation – ElitNows Nov 11 '21 at 12:25
  • @ElitNows you are welcome. Pls, mark the answer as accepted if it answers your conundrum. – floatingpurr Nov 11 '21 at 13:34
  • @ElitNows is there a reason why you are trying to handle this manually, instead of using Python's [`http.server`](https://docs.python.org/3/library/http.server.html) module, or any 3rd party HTTP server library for Python? – Remy Lebeau Nov 11 '21 at 21:22

1 Answers1

0

Here is a working example of what you need.

tl;dr: as pointed out in comments, with sockets you are working at the transport level. The HTTP Basic Auth lies at a higher level in the TCP/IP (or OSI) stack. If you do not want to embrace the HTTP protocol (do you?), you need to process requests and headers manually, mimicking the HTTP protocol. Indeed, python requests manages full-fledged HTTP requests.

I slightly modified your code to parse http headers and to manage a HTTP-like auth. There you go (comments and explanation in the code):

import socket, base64
from http.server import BaseHTTPRequestHandler
from io import BytesIO

serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverPort = 8080
serverSocket.bind(("127.0.0.1", serverPort))
serverSocket.listen(1)

# Auth section
user = 'user'
password = 'pass'
# The token you want the client to provide (string)
server_token = base64.b64encode(bytes(f'{user}:{password}','utf-8')).decode('utf-8')


# Use this simple class to parse you HTTP headers
# Read more here: https://stackoverflow.com/a/5955949/4820341
class HTTPRequest(BaseHTTPRequestHandler):
    def __init__(self, request_text):
        self.rfile = BytesIO(request_text)
        self.raw_requestline = self.rfile.readline()
        self.error_code = self.error_message = None
        self.parse_request()

    def send_error(self, code, message):
        self.error_code = code
        self.error_message = message



while True:
    print('Ready to serve...')

    connectionSocket, addr = serverSocket.accept()

    data = connectionSocket.recv(1024)

    # Those are your data coming from the client
    print(data.decode('utf-8'))

    # parse your headers
    http_headers = HTTPRequest(data)

    try:

        # get the incoming auth token
        client_token = http_headers.headers['Authorization'].strip('Basic ')

        if server_token != client_token:
            connectionSocket.sendall(bytes("HTTP/1.1 401 Unauthorized\n\n" + 'Wrong credetials', 'utf-8'))
        else:
            # process the request and do your stuff here
            connectionSocket.sendall(bytes("HTTP/1.1 200 OK\n\n" + 'Ok, all is fine here', 'utf-8'))

    except AttributeError:
        connectionSocket.sendall(bytes("HTTP/1.1 401 Unauthorized\n\n" + 'No credentials provided', 'utf-8'))

    finally:
        connectionSocket.close()

Here is how a requests.get with auth looks like server side:

Ready to serve...
GET / HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: python-requests/2.26.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Authorization: Basic dXNlcjpwYXNz

And now, let's see it in action:

>>> r = requests.get('http://127.0.0.1:8080',auth = HTTPBasicAuth('user', 'pass'))
>>> r.status_code
200
>>> r.text
'Ok, all is fine here'
>>>
>>>
>>> r = requests.get('http://127.0.0.1:8080',auth = HTTPBasicAuth('user', 'wrongpass'))
>>> r.status_code
401
>>> r.text
'wrong credentials'
>>>
>>>
>>> r = requests.get('http://127.0.0.1:8080')
>>> r.status_code
401
>>> r.text
'No credentials provided'
floatingpurr
  • 7,749
  • 9
  • 46
  • 106