* refactor(chalice): upgraded dependencies

* refactor(chalice): upgraded dependencies
feat(chalice): support heatmaps

* fix(chalice): fixed Math-operators validation
refactor(chalice): search for sessions that have events for heatmaps

* refactor(chalice): search for sessions that have at least 1 location event for heatmaps

* refactor(chalice): upgraded dependencies

* refactor(chalice): upgraded dependencies
feat(chalice): support heatmaps

* fix(chalice): fixed Math-operators validation
refactor(chalice): search for sessions that have events for heatmaps

* refactor(chalice): search for sessions that have at least 1 location event for heatmaps

* refactor(chalice): upgraded dependencies
refactor(crons): upgraded dependencies
refactor(alerts): upgraded dependencies

* feat(chalice): get top 10 values for autocomplete CH

* refactor(chalice): cleaned code
refactor(chalice): upgraded dependencies
refactor(alerts): upgraded dependencies
refactor(crons): upgraded dependencies

* feat(chalice): autocomplete return top 10 with stats

* fix(chalice): fixed autocomplete top 10 meta-filters

* refactor(chalice): refactored SSO ACS logic
This commit is contained in:
Kraiem Taha Yassine 2024-08-01 16:33:31 +02:00 committed by GitHub
parent b24da71456
commit 66c6051890
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 36 additions and 147 deletions

View file

@ -860,7 +860,7 @@ def refresh(user_id: int, tenant_id: int) -> dict:
}
def authenticate_sso(email: str, internal_id: str, exp=None, include_spot: bool = False):
def authenticate_sso(email: str, internal_id: str, include_spot: bool = False):
with pg_client.PostgresClient() as cur:
query = cur.mogrify(
f"""SELECT

View file

@ -28,9 +28,7 @@ async def start_sso(request: Request, iFrame: bool = False, spot: bool = False):
return RedirectResponse(url=sso_built_url)
@public_app.post('/sso/saml2/acs', tags=["saml2"])
@public_app.post('/sso/saml2/acs/', tags=["saml2"])
async def process_sso_assertion(request: Request):
async def __process_assertion(request: Request, tenant_key=None):
req = await prepare_request(request=request)
session = req["cookie"]["session"]
auth = init_saml_auth(req)
@ -66,7 +64,6 @@ async def process_sso_assertion(request: Request):
auth.process_response(request_id=request_id)
errors = auth.get_errors()
user_data = {}
if len(errors) == 0:
if 'AuthNRequestID' in session:
del session['AuthNRequestID']
@ -78,11 +75,14 @@ async def process_sso_assertion(request: Request):
return {"errors": [error_reason]}
email = auth.get_nameid()
logger.debug(f"received nameId: {email}")
existing = users.get_by_email_only(auth.get_nameid())
if tenant_key is None:
tenant_key = user_data.get("tenantKey", [])
else:
logger.info("Using tenant key from ACS-URL")
internal_id = next(iter(user_data.get("internalId", [])), None)
tenant_key = user_data.get("tenantKey", [])
logger.debug(f"received nameId: {email} tenant_key: {tenant_key}")
logger.debug(">user_data:")
logger.debug(user_data)
if len(tenant_key) == 0:
logger.error("tenantKey not present in assertion, please check your SP-assertion-configuration")
return {"errors": ["tenantKey not present in assertion, please check your SP-assertion-configuration"]}
@ -91,22 +91,24 @@ async def process_sso_assertion(request: Request):
if t is None:
logger.error("invalid tenantKey, please copy the correct value from Preferences > Account")
return {"errors": ["invalid tenantKey, please copy the correct value from Preferences > Account"]}
logger.debug(user_data)
role_name = user_data.get("role", [])
if len(role_name) == 0:
logger.info("No role specified, setting role to member")
role_name = ["member"]
role_name = role_name[0]
role = roles.get_role_by_name(tenant_id=t['tenantId'], name=role_name)
if role is None:
return {"errors": [f"role {role_name} not found, please create it in openreplay first"]}
admin_privileges = user_data.get("adminPrivileges", [])
admin_privileges = not (len(admin_privileges) == 0
or admin_privileges[0] is None
or admin_privileges[0].lower() == "false")
existing = users.get_by_email_only(auth.get_nameid())
internal_id = next(iter(user_data.get("internalId", [])), None)
if existing is None:
role_name = user_data.get("role", [])
if len(role_name) == 0:
logger.info("No role specified, setting role to member")
role_name = ["member"]
role_name = role_name[0]
role = roles.get_role_by_name(tenant_id=t['tenantId'], name=role_name)
if role is None:
return {"errors": [f"role {role_name} not found, please create it in openreplay first"]}
admin_privileges = user_data.get("adminPrivileges", [])
admin_privileges = not (len(admin_privileges) == 0
or admin_privileges[0] is None
or admin_privileges[0].lower() == "false")
deleted = users.get_deleted_user_by_email(auth.get_nameid())
if deleted is not None:
logger.info("== restore deleted user ==")
@ -128,146 +130,33 @@ async def process_sso_assertion(request: Request):
logger.info(f"== migrating user to {SAML2_helper.get_saml2_provider()} ==")
users.update(tenant_id=t['tenantId'], user_id=existing["userId"],
changes={"origin": SAML2_helper.get_saml2_provider(), "internal_id": internal_id})
expiration = auth.get_session_expiration()
logger.warning(">>>>>>>>")
logger.warning(expiration)
expiration = expiration if expiration is not None and expiration > 10 * 60 \
else int(config("sso_exp_delta_seconds", cast=int, default=24 * 60 * 60))
jwt = users.authenticate_sso(email=email, internal_id=internal_id, exp=expiration, include_spot=spot)
jwt = users.authenticate_sso(email=email, internal_id=internal_id, include_spot=spot)
if jwt is None:
return {"errors": ["null JWT"]}
response = Response(status_code=status.HTTP_302_FOUND)
response.set_cookie(key="refreshToken", value=jwt["refreshToken"], path="/api/refresh",
max_age=jwt["refreshTokenMaxAge"], secure=True, httponly=True)
query_params = {"jwt": jwt["jwt"]}
if spot:
response.set_cookie(key="spotRefreshToken", value=jwt["spotRefreshToken"], path="/api/spot/refresh",
max_age=jwt["spotRefreshTokenMaxAge"], secure=True, httponly=True)
headers = {'Location': SAML2_helper.get_landing_URL({"jwt": jwt["jwt"], "spotJwt": jwt["spotJwt"]},
redirect_to_link2=redirect_to_link2)}
else:
headers = {'Location': SAML2_helper.get_landing_URL({"jwt": jwt["jwt"]}, redirect_to_link2=redirect_to_link2)}
query_params["spotJwt"] = jwt["spotJwt"]
headers = {'Location': SAML2_helper.get_landing_URL(query_params=query_params, redirect_to_link2=redirect_to_link2)}
response.init_headers(headers)
return response
@public_app.post('/sso/saml2/acs', tags=["saml2"])
@public_app.post('/sso/saml2/acs/', tags=["saml2"])
async def process_sso_assertion(request: Request):
return await __process_assertion(request)
@public_app.post('/sso/saml2/acs/{tenantKey}', tags=["saml2"])
@public_app.post('/sso/saml2/acs/{tenantKey}/', tags=["saml2"])
async def process_sso_assertion_tk(tenantKey: str, request: Request):
req = await prepare_request(request=request)
session = req["cookie"]["session"]
auth = init_saml_auth(req)
post_data = req.get("post_data")
if post_data is None:
post_data = {}
elif isinstance(post_data, str):
post_data = json.loads(post_data)
elif not isinstance(post_data, dict):
logger.error("Received invalid post_data")
logger.error("type: {}".format(type(post_data)))
logger.error(post_data)
post_data = {}
redirect_to_link2 = None
spot = False
relay_state = post_data.get('RelayState')
if relay_state:
if isinstance(relay_state, str):
relay_state = json.loads(relay_state)
elif not isinstance(relay_state, dict):
logger.error("Received invalid relay_state")
logger.error("type: {}".format(type(relay_state)))
logger.error(relay_state)
relay_state = {}
redirect_to_link2 = relay_state.get("iFrame")
spot = relay_state.get("spot")
request_id = None
if 'AuthNRequestID' in session:
request_id = session['AuthNRequestID']
auth.process_response(request_id=request_id)
errors = auth.get_errors()
user_data = {}
if len(errors) == 0:
if 'AuthNRequestID' in session:
del session['AuthNRequestID']
user_data = auth.get_attributes()
else:
error_reason = auth.get_last_error_reason()
logger.error("SAML2 error:")
logger.error(error_reason)
return {"errors": [error_reason]}
email = auth.get_nameid()
logger.debug(f"received nameId: {email}")
existing = users.get_by_email_only(auth.get_nameid())
internal_id = next(iter(user_data.get("internalId", [])), None)
t = tenants.get_by_tenant_key(tenantKey)
if t is None:
logger.error("invalid tenantKey, please copy the correct value from Preferences > Account")
return {"errors": ["invalid tenantKey, please copy the correct value from Preferences > Account"]}
logger.debug(user_data)
role_name = user_data.get("role", [])
if len(role_name) == 0:
logger.info("No role specified, setting role to member")
role_name = ["member"]
role_name = role_name[0]
role = roles.get_role_by_name(tenant_id=t['tenantId'], name=role_name)
if role is None:
return {"errors": [f"role {role_name} not found, please create it in openreplay first"]}
admin_privileges = user_data.get("adminPrivileges", [])
admin_privileges = not (len(admin_privileges) == 0
or admin_privileges[0] is None
or admin_privileges[0].lower() == "false")
if existing is None:
deleted = users.get_deleted_user_by_email(auth.get_nameid())
if deleted is not None:
logger.info("== restore deleted user ==")
users.restore_sso_user(user_id=deleted["userId"], tenant_id=t['tenantId'], email=email,
admin=admin_privileges, origin=SAML2_helper.get_saml2_provider(),
name=" ".join(user_data.get("firstName", []) + user_data.get("lastName", [])),
internal_id=internal_id, role_id=role["roleId"])
else:
logger.info("== new user ==")
users.create_sso_user(tenant_id=t['tenantId'], email=email, admin=admin_privileges,
origin=SAML2_helper.get_saml2_provider(),
name=" ".join(user_data.get("firstName", []) + user_data.get("lastName", [])),
internal_id=internal_id, role_id=role["roleId"])
else:
if t['tenantId'] != existing["tenantId"]:
logger.warning("user exists for a different tenant")
return {"errors": ["user exists for a different tenant"]}
if existing.get("origin") is None:
logger.info(f"== migrating user to {SAML2_helper.get_saml2_provider()} ==")
users.update(tenant_id=t['tenantId'], user_id=existing["userId"],
changes={"origin": SAML2_helper.get_saml2_provider(), "internal_id": internal_id})
expiration = auth.get_session_expiration()
logger.warning(">>>>>>>>")
logger.warning(expiration)
expiration = expiration if expiration is not None and expiration > 10 * 60 \
else int(config("sso_exp_delta_seconds", cast=int, default=24 * 60 * 60))
jwt = users.authenticate_sso(email=email, internal_id=internal_id, exp=expiration, include_spot=spot)
if jwt is None:
return {"errors": ["null JWT"]}
response = Response(status_code=status.HTTP_302_FOUND)
response.set_cookie(key="refreshToken", value=jwt["refreshToken"], path="/api/refresh",
max_age=jwt["refreshTokenMaxAge"], secure=True, httponly=True)
if spot:
response.set_cookie(key="spotRefreshToken", value=jwt["spotRefreshToken"], path="/api/spot/refresh",
max_age=jwt["spotRefreshTokenMaxAge"], secure=True, httponly=True)
headers = {'Location': SAML2_helper.get_landing_URL({"jwt": jwt["jwt"], "spotJwt": jwt["spotJwt"]},
redirect_to_link2=redirect_to_link2)}
else:
headers = {'Location': SAML2_helper.get_landing_URL({"jwt": jwt["jwt"]}, redirect_to_link2=redirect_to_link2)}
response.init_headers(headers)
return response
return await __process_assertion(request, tenantKey)
@public_app.get('/sso/saml2/sls', tags=["saml2"])