I am facing a reverse proxy with nginx and FastAPI while integrating SAML SSO with OneLogin. I get the ERROR:routers.auth:Errors occurred: ['invalid_response']
followed by The response was received at https://containerip/ instead of https:myserverurl
Here's my nginx config
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name $hostname ;
# SSL
ssl_certificate /etc/nginx/ssl/localhost.crt;
ssl_certificate_key /etc/nginx/ssl/localhost.key;
# security
include nginxconfig.io/security.conf;
# restrict methods
if ($request_method !~ ^(GET|POST)$) {
return '405';
}
# New location for FastAPI-App
location / {
proxy_pass http://fastapi:5000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
This is how I am preparing the request for auth:
async def prepare_fastapi_request(request):
# Convert FastAPI request to a format compatible with python3-saml
form_data = await request.form()
server_port = request.url.port
if server_port is None:
server_port = "443" if request.url.scheme == "https" else "80"
rv = {
"https": "on" if request.url.scheme == "https" else "off",
"http_host": request.client.host,
"server_port": server_port,
"script_name": request.url.path,
"get_data": { },
# "post_data": await request.form(), # Changed this
"post_data": { }, # Use this instead
}
if (request.query_params):
rv["get_data"] = request.query_params,
if "SAMLResponse" in form_data:
SAMLResponse = form_data["SAMLResponse"]
rv["post_data"]["SAMLResponse"] = SAMLResponse
if "RelayState" in form_data:
RelayState = form_data["RelayState"]
rv["post_data"]["RelayState"] = RelayState
return rv
This is the CMD to run my docker container on the server:
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "5000", "--proxy-headers", "--forwarded-allow-ips", "*"]
I tried solutions using proxy headers, X-forwarded, proxy redirect, but nothing seems to work, I also changed the RelayState to the url of my service hosted on the server.
The problem was resolved by changing the following function
async def prepare_fastapi_request(request):
headers = request.headers
forwarded_host = headers.get("x-forwarded-host")
server_port = headers.get("x-forwarded-port")
rv = {
"https": "on" if request.url.scheme == "https" else "off",
"http_host": forwarded_host,
"server_port": server_port,
"script_name": request.url.path,
"get_data": request.query_params,
"post_data": await request.form(), # Changed this
#"post_data": { }, # Use this instead
}
return rv