Skip to content
Snippets Groups Projects
Commit 2c5adf30 authored by Jan Hartig's avatar Jan Hartig
Browse files

implement ip based access

parent 1f967468
Branches
No related tags found
1 merge request!27Implement ip based access
Pipeline #48931 passed
sanic~=23.6.0 sanic~=24.12.0
aiofiles~=23.2.1 aiofiles~=24.1.0
wonderwords~=2.2.0 wonderwords~=2.2.0
\ No newline at end of file
...@@ -11,6 +11,7 @@ from sanic.exceptions import Unauthorized, InvalidUsage ...@@ -11,6 +11,7 @@ from sanic.exceptions import Unauthorized, InvalidUsage
from sanic.response import json as json_response from sanic.response import json as json_response
from sanic.response import redirect from sanic.response import redirect
from wonderwords import RandomWord from wonderwords import RandomWord
import ipaddress
app = Sanic(__name__) app = Sanic(__name__)
r = RandomWord() r = RandomWord()
...@@ -22,6 +23,7 @@ SANIC_JITSI_APP_ID ...@@ -22,6 +23,7 @@ SANIC_JITSI_APP_ID
SANIC_JITSI_APP_SECRET: Jitsi App Secret SANIC_JITSI_APP_SECRET: Jitsi App Secret
SANIC_TOKEN_VALID_FOR: Time in seconds generated personal room JWT will be valid for SANIC_TOKEN_VALID_FOR: Time in seconds generated personal room JWT will be valid for
SANIC_ROOMS_VALID_FOR: Time in days generated room JWT will be valid for SANIC_ROOMS_VALID_FOR: Time in days generated room JWT will be valid for
SANIC_ALLOWED_IPS: Client IPs allowed to generate tokens, only IPv4, comma seperated "192.168.0.1/24,172.20.0.1/24"
""" """
# Static token header string # Static token header string
...@@ -31,6 +33,8 @@ header = json.dumps({"typ": "JWT", "alg": "HS256"}, separators=(",", ":")).encod ...@@ -31,6 +33,8 @@ header = json.dumps({"typ": "JWT", "alg": "HS256"}, separators=(",", ":")).encod
ROOMS_VALID_FOR_S = app.config.ROOMS_VALID_FOR * 24 * 60 * 60 # d, h, m -> s ROOMS_VALID_FOR_S = app.config.ROOMS_VALID_FOR * 24 * 60 * 60 # d, h, m -> s
ALLOWED_IPS = {ipaddress.IPv4Network(entry) for entry in app.config.ALLOWED_IPS.split(",")}
@app.post("/unlockroom") @app.post("/unlockroom")
async def unlock_room(request: Request): async def unlock_room(request: Request):
...@@ -65,6 +69,10 @@ async def unlock_room(request: Request): ...@@ -65,6 +69,10 @@ async def unlock_room(request: Request):
@app.route("/cert2room") @app.route("/cert2room")
async def cert2room(request: Request): async def cert2room(request: Request):
dn = check_auth(request) dn = check_auth(request)
if dn is None:
room = get_random_room()
serial = request.headers.get("SSL-Client-Serial") serial = request.headers.get("SSL-Client-Serial")
if serial: if serial:
...@@ -81,23 +89,32 @@ async def cert2room(request: Request): ...@@ -81,23 +89,32 @@ async def cert2room(request: Request):
# Serial not found, build room from name # Serial not found, build room from name
room = dn["CN"] room = dn["CN"]
# Make room name url-safe # Make room name url-safe
room = quote(room) room = quote(room)
# Generate jwt
jwt = gen_jwt(room, app.config.TOKEN_VALID_FOR)
# redirect to room # Generate jwt
return redirect("/{}?jwt={}".format(room, jwt)) jwt = gen_jwt(room, app.config.TOKEN_VALID_FOR)
raise InvalidUsage # redirect to room
return redirect("/{}?jwt={}".format(room, jwt))
def check_auth(request: Request) -> dict: def check_auth(request: Request) -> dict | None:
s_dn = request.headers.get("SSL-Client-S-DN") s_dn = request.headers.get("SSL-Client-S-DN")
if not s_dn: if not s_dn:
raise InvalidUsage client_ip = ipaddress.IPv4Address(request.headers.get("CLient-IP"))
allowed = False
for network in ALLOWED_IPS:
if client_ip in network:
allowed = True
break
if not allowed:
raise Unauthorized("Unauthorized")
return None
# Turn distinguished names string into dict # Turn distinguished names string into dict
dn = dict(item.split("=") for item in s_dn.split(",")) dn = dict(item.split("=") for item in s_dn.split(","))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment