Dominik 2 months ago
parent
commit
aaec6759c8
1 changed files with 165 additions and 0 deletions
  1. 165 0
      CODE-EXPLAINED.md

+ 165 - 0
CODE-EXPLAINED.md

@@ -0,0 +1,165 @@
+Some explanation on components used for the authentication proxy...
+
+
+### Show simple page
+Creates an object of the class [HTTPServer](https://docs.python.org/3/library/http.server.html) which takes as parameter:
+  - a tuple of (host, port) to bind. Empty host binds to all interfaces.
+  - an object of the class BaseHTTPRequestHandlerto to answer http requests, e.g. GET, POST, ...
+
+```
+from http.server import BaseHTTPRequestHandler, HTTPServer
+httpd = HTTPServer(('', 8000), BaseHTTPRequestHandler)
+httpd.serve_forever()
+```
+
+To actually answer http requests, a new class has to be defined
+which inherits BaseHTTPRequestHandler an overwrites the functions
+to handle different http request types such a GET, POST, ...
+```
+from http.server import BaseHTTPRequestHandler, HTTPServer
+
+HOST='localhost'
+PORT=8000
+
+s = """<html>
+<head><title>hello, world</title></head>
+<body>hello, world</body>
+</html>"""
+
+class OtpRequestHandler(BaseHTTPRequestHandler):
+    def do_GET(self):
+        self.send_response(200) #OK
+        self.send_header("Content-type", "text/html")
+        self.end_headers()
+        self.wfile.write(bytes(s, "utf-8"))
+
+httpd = HTTPServer((HOST, PORT), OtpRequestHandler)
+httpd.serve_forever()
+```
+
+To test: `curl http://localhost:8000/`
+
+
+
+### Print POST data
+- To read data received via post we need to obtain the length
+  of the post data from the http-header first.
+- Form data is sent with the content-type application/x-www-form-urlencoded
+
+```
+from http.server import BaseHTTPRequestHandler, HTTPServer
+
+class OtpRequestHandler(BaseHTTPRequestHandler):
+    def do_POST(self):
+        length = int(self.headers['Content-Length'])
+        print(self.headers['content-type'])
+        print(self.rfile.read(length))
+        
+httpd = HTTPServer(('localhost', 8000), OtpRequestHandler)
+httpd.serve_forever()
+```
+
+To Test: `curl -d "hello, world" -X POST http://localhost:8000/`
+
+
+
+### Parse HTML form data
+- parse_qs parses the form data into a dictionary.
+- Form values are stored as list in the dicionary,
+  which has to be converted to a string
+
+```
+from http.server import BaseHTTPRequestHandler, HTTPServer
+from urllib.parse import parse_qs
+
+class OtpRequestHandler(BaseHTTPRequestHandler):
+    def do_POST(self):
+        length = int(self.headers['Content-Length'])
+        parms = parse_qs(self.rfile.read(length).decode("utf-8"))
+        print("User: " + ''.join(parms["user"]) )
+        print("OTP: "  + ''.join(parms["otp"]) )
+
+httpd = HTTPServer(('localhost', 8000), OtpRequestHandler)
+httpd.serve_forever()
+```
+
+To Test: `curl -d "user=jdoe&otp=204177" -X POST http://localhost:8000/`
+
+
+
+### Set Cookie
+```
+from http.server import BaseHTTPRequestHandler, HTTPServer
+from http.cookies import SimpleCookie
+import secrets
+
+cookie = SimpleCookie()
+cookie['token'] = secrets.token_urlsafe(16)
+#cookie["token"]["domain"] = "s-up.net"
+cookie["token"]["path"] = "/"
+#cookie["token"]["secure"] = True
+cookie["token"]["httponly"] = True
+cookies.Morsel._reserved.setdefault('samesite', 'SameSite')
+cookie["token"]["samesite"] = "strict"
+cookie["token"]["expires"] = 60 * 60 * 6 # 6h
+
+class OtpRequestHandler(BaseHTTPRequestHandler):
+    def do_GET(self):
+        self.send_response(200) #OK
+        self.send_header("Content-type", "text/html")
+        self.send_header('Set-Cookie', cookie.output(header=''))
+        self.end_headers()
+        self.wfile.write(bytes("Hello", "utf-8"))
+
+httpd = HTTPServer(('localhost', 8000), OtpRequestHandler)
+httpd.serve_forever()
+```
+
+### Get Cookie
+```
+from http.server import BaseHTTPRequestHandler, HTTPServer
+from http.cookies import SimpleCookie
+import secrets
+
+class OtpRequestHandler(BaseHTTPRequestHandler):
+    def do_GET(self):
+        self.send_response(200) #OK
+        self.send_header("Content-type", "text/html")
+        self.end_headers()
+        cookies = SimpleCookie(self.headers.get('Cookie'))
+        token = cookies['token'].value
+        self.wfile.write(bytes(token, "utf-8"))
+        print(token)
+
+httpd = HTTPServer(('localhost', 8000), OtpRequestHandler)
+httpd.serve_forever()
+```
+
+
+
+### TOTP
+```
+import pyotp
+import time
+
+# Get a random secret
+secret=pyotp.random_base32()
+print(secret)
+
+# Calculate OTP
+otp=pyotp.TOTP(secret).now()
+print(otp)
+
+# Verify OTP, should be true
+pyotp.TOTP(secret).verify(otp)
+
+# Verify OTP again after 30s, should be false
+time.sleep(30)
+pyotp.TOTP(secret).verify(otp)
+```
+
+
+## References
+
+- [Online TOTP Generator](https://totp.danhersam.com/)
+- [simpleotp on Github](https://github.com/newhouseb/simpleotp)