feature(chalice): support multi SSO redirect
This commit is contained in:
parent
4e190cc00d
commit
19470cd41f
4 changed files with 37 additions and 16 deletions
|
|
@ -15,16 +15,16 @@ fastapi = "==0.104.1"
|
|||
gunicorn = "==21.2.0"
|
||||
python-decouple = "==3.8"
|
||||
apscheduler = "==3.10.4"
|
||||
python3-saml = "==1.16.0"
|
||||
python-multipart = "==0.0.6"
|
||||
redis = "==5.0.1"
|
||||
python3-saml = "==1.16.0"
|
||||
azure-storage-blob = "==12.19.0"
|
||||
psycopg = {extras = ["binary", "pool"], version = "==3.1.14"}
|
||||
uvicorn = {extras = ["standard"], version = "==0.23.2"}
|
||||
pydantic = {extras = ["email"], version = "==2.3.0"}
|
||||
clickhouse-driver = {extras = ["lz4"], version = "==0.2.6"}
|
||||
psycopg = {extras = ["binary", "pool"], version = "==3.1.12"}
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[requires]
|
||||
python_version = "3.11"
|
||||
python_version = "3.12"
|
||||
|
|
|
|||
|
|
@ -10,17 +10,18 @@ from starlette.datastructures import FormData
|
|||
if config("ENABLE_SSO", cast=bool, default=True):
|
||||
from onelogin.saml2.auth import OneLogin_Saml2_Auth
|
||||
|
||||
API_PREFIX = "/api"
|
||||
SAML2 = {
|
||||
"strict": config("saml_strict", cast=bool, default=True),
|
||||
"debug": config("saml_debug", cast=bool, default=True),
|
||||
"sp": {
|
||||
"entityId": config("SITE_URL") + "/api/sso/saml2/metadata/",
|
||||
"entityId": config("SITE_URL") + API_PREFIX + "/sso/saml2/metadata/",
|
||||
"assertionConsumerService": {
|
||||
"url": config("SITE_URL") + "/api/sso/saml2/acs/",
|
||||
"url": config("SITE_URL") + API_PREFIX + "/sso/saml2/acs/",
|
||||
"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
||||
},
|
||||
"singleLogoutService": {
|
||||
"url": config("SITE_URL") + "/api/sso/saml2/sls/",
|
||||
"url": config("SITE_URL") + API_PREFIX + "/sso/saml2/sls/",
|
||||
"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
||||
},
|
||||
"NameIDFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
|
||||
|
|
@ -110,8 +111,8 @@ async def prepare_request(request: Request):
|
|||
# add / to /acs
|
||||
if not path.endswith("/"):
|
||||
path = path + '/'
|
||||
if not path.startswith("/api"):
|
||||
path = "/api" + path
|
||||
if len(API_PREFIX) > 0 and not path.startswith(API_PREFIX):
|
||||
path = API_PREFIX + path
|
||||
|
||||
return {
|
||||
'https': 'on' if proto == 'https' else 'off',
|
||||
|
|
@ -136,7 +137,13 @@ def get_saml2_provider():
|
|||
config("idp_name", default="saml2")) > 0 else None
|
||||
|
||||
|
||||
def get_landing_URL(jwt):
|
||||
def get_landing_URL(jwt, redirect_to_link2=False):
|
||||
if redirect_to_link2:
|
||||
if len(config("sso_landing_override", default="")) == 0:
|
||||
logging.warning("SSO trying to redirect to custom URL, but sso_landing_override env var is empty")
|
||||
else:
|
||||
return config("sso_landing_override") + "?jwt=%s" % jwt
|
||||
|
||||
return config("SITE_URL") + config("sso_landing", default="/login?jwt=%s") % jwt
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16,12 +16,15 @@ mkdir .venv
|
|||
|
||||
# Installing dependencies (pipenv will detect the .venv folder and use it as a target)
|
||||
pipenv install -r requirements.txt [--skip-lock]
|
||||
|
||||
# These commands must bu used everytime you make changes to FOSS.
|
||||
# To clean the unused files before getting new ones
|
||||
bash clean.sh
|
||||
# To copy commun files from FOSS
|
||||
bash prepare-dev.sh
|
||||
|
||||
# In case of an issue with python3-saml installation for MacOS,
|
||||
# please follow these instructions:
|
||||
https://github.com/xmlsec/python-xmlsec/issues/254#issuecomment-1726249435
|
||||
```
|
||||
|
||||
### Building and deploying locally
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import json
|
||||
import logging
|
||||
|
||||
from fastapi import HTTPException, Request, Response, status
|
||||
|
||||
from chalicelib.utils import SAML2_helper
|
||||
from chalicelib.utils.SAML2_helper import prepare_request, init_saml_auth
|
||||
from routers.base import get_routers
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -18,11 +20,11 @@ from starlette.responses import RedirectResponse
|
|||
|
||||
@public_app.get("/sso/saml2", tags=["saml2"])
|
||||
@public_app.get("/sso/saml2/", tags=["saml2"])
|
||||
async def start_sso(request: Request):
|
||||
async def start_sso(request: Request, iFrame: bool = False):
|
||||
request.path = ''
|
||||
req = await prepare_request(request=request)
|
||||
auth = init_saml_auth(req)
|
||||
sso_built_url = auth.login()
|
||||
sso_built_url = auth.login(return_to=json.dumps({'iFrame': iFrame}))
|
||||
return RedirectResponse(url=sso_built_url)
|
||||
|
||||
|
||||
|
|
@ -33,6 +35,8 @@ async def process_sso_assertion(request: Request):
|
|||
session = req["cookie"]["session"]
|
||||
auth = init_saml_auth(req)
|
||||
|
||||
redirect_to_link2 = json.loads(req.get("post_data", {}) \
|
||||
.get('RelayState', '{}')).get("iFrame")
|
||||
request_id = None
|
||||
if 'AuthNRequestID' in session:
|
||||
request_id = session['AuthNRequestID']
|
||||
|
|
@ -111,7 +115,7 @@ async def process_sso_assertion(request: Request):
|
|||
refresh_token_max_age = jwt["refreshTokenMaxAge"]
|
||||
response = Response(
|
||||
status_code=status.HTTP_302_FOUND,
|
||||
headers={'Location': SAML2_helper.get_landing_URL(jwt["jwt"])})
|
||||
headers={'Location': SAML2_helper.get_landing_URL(jwt["jwt"], redirect_to_link2=redirect_to_link2)})
|
||||
response.set_cookie(key="refreshToken", value=refresh_token, path="/api/refresh",
|
||||
max_age=refresh_token_max_age, secure=True, httponly=True)
|
||||
return response
|
||||
|
|
@ -124,6 +128,8 @@ async def process_sso_assertion_tk(tenantKey: str, request: Request):
|
|||
session = req["cookie"]["session"]
|
||||
auth = init_saml_auth(req)
|
||||
|
||||
redirect_to_link2 = json.loads(req.get("post_data", {}) \
|
||||
.get('RelayState', '{}')).get("iFrame")
|
||||
request_id = None
|
||||
if 'AuthNRequestID' in session:
|
||||
request_id = session['AuthNRequestID']
|
||||
|
|
@ -194,9 +200,14 @@ async def process_sso_assertion_tk(tenantKey: str, request: Request):
|
|||
jwt = users.authenticate_sso(email=email, internal_id=internal_id, exp=expiration)
|
||||
if jwt is None:
|
||||
return {"errors": ["null JWT"]}
|
||||
return Response(
|
||||
refresh_token = jwt["refreshToken"]
|
||||
refresh_token_max_age = jwt["refreshTokenMaxAge"]
|
||||
response = Response(
|
||||
status_code=status.HTTP_302_FOUND,
|
||||
headers={'Location': SAML2_helper.get_landing_URL(jwt)})
|
||||
headers={'Location': SAML2_helper.get_landing_URL(jwt["jwt"], redirect_to_link2=redirect_to_link2)})
|
||||
response.set_cookie(key="refreshToken", value=refresh_token, path="/api/refresh",
|
||||
max_age=refresh_token_max_age, secure=True, httponly=True)
|
||||
return response
|
||||
|
||||
|
||||
@public_app.get('/sso/saml2/sls', tags=["saml2"])
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue