* 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

* 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

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

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

* refactor(chalice): always generate spot-jwt
refactor(chalice): generate spot-jwt on password change
refactor(chalice): generate spot-jwt on accept invitation
This commit is contained in:
Kraiem Taha Yassine 2024-09-06 16:02:07 +02:00 committed by GitHub
parent 2d8ff056c4
commit 25e6862ce6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 158 additions and 169 deletions

View file

@ -6,9 +6,9 @@ from fastapi import BackgroundTasks
from pydantic import BaseModel
import schemas
from chalicelib.core import authorizers, metadata, projects
from chalicelib.core import tenants, assist, spot
from chalicelib.utils import email_helper, smtp
from chalicelib.core import authorizers, metadata
from chalicelib.core import tenants, spot, scope
from chalicelib.utils import email_helper
from chalicelib.utils import helper
from chalicelib.utils import pg_client
from chalicelib.utils.TimeUTC import TimeUTC
@ -209,7 +209,7 @@ def get(user_id, tenant_id):
users.user_id,
email,
role,
name,
users.name,
(CASE WHEN role = 'owner' THEN TRUE ELSE FALSE END) AS super_admin,
(CASE WHEN role = 'admin' THEN TRUE ELSE FALSE END) AS admin,
(CASE WHEN role = 'member' THEN TRUE ELSE FALSE END) AS member,
@ -458,16 +458,16 @@ def set_password_invitation(user_id, new_password):
"projects": -1,
"metadata": metadata.get_remaining_metadata_with_count(tenant_id)}
c = tenants.get_by_tenant_id(tenant_id)
c.pop("createdAt")
c["projects"] = projects.get_projects(tenant_id=tenant_id, recorded=True)
c["smtp"] = smtp.has_smtp()
c["iceServers"] = assist.get_ice_servers()
return {
'jwt': r.pop('jwt'),
"jwt": r.pop("jwt"),
"refreshToken": r.pop("refreshToken"),
"refreshTokenMaxAge": r.pop("refreshTokenMaxAge"),
"spotJwt": r.pop("spotJwt"),
"spotRefreshToken": r.pop("spotRefreshToken"),
"spotRefreshTokenMaxAge": r.pop("spotRefreshTokenMaxAge"),
'data': {
"user": r,
"client": c
"scopeState": scope.get_scope(-1),
"user": r
}
}
@ -560,32 +560,27 @@ class ChangeJwt(BaseModel):
jwt_iat: int
jwt_refresh_jti: int
jwt_refresh_iat: int
spot_jwt_iat: int | None = None
spot_jwt_refresh_jti: int | None = None
spot_jwt_refresh_iat: int | None = None
spot_jwt_iat: int
spot_jwt_refresh_jti: int
spot_jwt_refresh_iat: int
def change_jwt_iat_jti(user_id, include_spot: bool = False):
sub_query = ""
sub_result = ""
if include_spot:
sub_query = """,spot_jwt_iat = timezone('utc'::text, now()-INTERVAL '10s'),
spot_jwt_refresh_jti = 0,
spot_jwt_refresh_iat = timezone('utc'::text, now()-INTERVAL '10s')"""
sub_result = """,EXTRACT (epoch FROM spot_jwt_iat)::BIGINT AS spot_jwt_iat,
spot_jwt_refresh_jti,
EXTRACT (epoch FROM spot_jwt_refresh_iat)::BIGINT AS spot_jwt_refresh_iat"""
def change_jwt_iat_jti(user_id):
with pg_client.PostgresClient() as cur:
query = cur.mogrify(f"""UPDATE public.users
SET jwt_iat = timezone('utc'::text, now()-INTERVAL '10s'),
jwt_refresh_jti = 0,
jwt_refresh_iat = timezone('utc'::text, now()-INTERVAL '10s')
{sub_query}
jwt_refresh_iat = timezone('utc'::text, now()-INTERVAL '10s'),
spot_jwt_iat = timezone('utc'::text, now()-INTERVAL '10s'),
spot_jwt_refresh_jti = 0,
spot_jwt_refresh_iat = timezone('utc'::text, now()-INTERVAL '10s')
WHERE user_id = %(user_id)s
RETURNING EXTRACT (epoch FROM jwt_iat)::BIGINT AS jwt_iat,
jwt_refresh_jti,
EXTRACT (epoch FROM jwt_refresh_iat)::BIGINT AS jwt_refresh_iat
{sub_result};""",
EXTRACT (epoch FROM jwt_refresh_iat)::BIGINT AS jwt_refresh_iat,
EXTRACT (epoch FROM spot_jwt_iat)::BIGINT AS spot_jwt_iat,
spot_jwt_refresh_jti,
EXTRACT (epoch FROM spot_jwt_refresh_iat)::BIGINT AS spot_jwt_refresh_iat;""",
{"user_id": user_id})
cur.execute(query)
row = cur.fetchone()
@ -607,7 +602,7 @@ def refresh_jwt_iat_jti(user_id):
return row.get("jwt_iat"), row.get("jwt_refresh_jti"), row.get("jwt_refresh_iat")
def authenticate(email, password, for_change_password=False, include_spot=False) -> dict | bool | None:
def authenticate(email, password, for_change_password=False) -> dict | bool | None:
with pg_client.PostgresClient() as cur:
query = cur.mogrify(
f"""SELECT
@ -632,7 +627,7 @@ def authenticate(email, password, for_change_password=False, include_spot=False)
if for_change_password:
return True
r = helper.dict_to_camel_case(r)
j_r = change_jwt_iat_jti(user_id=r['userId'], include_spot=include_spot)
j_r = change_jwt_iat_jti(user_id=r['userId'])
response = {
"jwt": authorizers.generate_jwt(user_id=r['userId'], tenant_id=r['tenantId'], iat=j_r.jwt_iat,
aud=AUDIENCE),
@ -641,22 +636,19 @@ def authenticate(email, password, for_change_password=False, include_spot=False)
jwt_jti=j_r.jwt_refresh_jti),
"refreshTokenMaxAge": config("JWT_REFRESH_EXPIRATION", cast=int),
"email": email,
"spotJwt": authorizers.generate_jwt(user_id=r['userId'], tenant_id=r['tenantId'],
iat=j_r.spot_jwt_iat, aud=spot.AUDIENCE, for_spot=True),
"spotRefreshToken": authorizers.generate_jwt_refresh(user_id=r['userId'],
tenant_id=r['tenantId'],
iat=j_r.spot_jwt_refresh_iat,
aud=spot.AUDIENCE,
jwt_jti=j_r.spot_jwt_refresh_jti,
for_spot=True),
"spotRefreshTokenMaxAge": config("JWT_SPOT_REFRESH_EXPIRATION", cast=int),
**r
}
if include_spot:
response = {
**response,
"spotJwt": authorizers.generate_jwt(user_id=r['userId'], tenant_id=r['tenantId'],
iat=j_r.spot_jwt_iat, aud=spot.AUDIENCE, for_spot=True),
"spotRefreshToken": authorizers.generate_jwt_refresh(user_id=r['userId'],
tenant_id=r['tenantId'],
iat=j_r.spot_jwt_refresh_iat,
aud=spot.AUDIENCE,
jwt_jti=j_r.spot_jwt_refresh_jti,
for_spot=True),
"spotRefreshTokenMaxAge": config("JWT_SPOT_REFRESH_EXPIRATION", cast=int)
}
return response
return None

View file

@ -20,6 +20,7 @@ from chalicelib.utils import helper
from chalicelib.utils.TimeUTC import TimeUTC
from or_dependencies import OR_context, OR_role
from routers.base import get_routers
from routers.subs import spot
logger = logging.getLogger(__name__)
public_app, app, app_apikey = get_routers()
@ -50,15 +51,36 @@ if not tenants.tenants_exists_sync(use_pool=False):
return content
def __process_authentication_response(response: JSONResponse, data: dict) -> dict:
data["smtp"] = smtp.has_smtp()
refresh_token = data.pop("refreshToken")
refresh_token_max_age = data.pop("refreshTokenMaxAge")
spot_refresh_token = data.pop("spotRefreshToken")
spot_refresh_token_max_age = data.pop("spotRefreshTokenMaxAge")
data = {
'jwt': data.pop('jwt'),
"spotJwt": data.pop("spotJwt"),
'data': {
"scopeState": scope.get_scope(-1),
"user": data
}
}
response.set_cookie(key="refreshToken", value=refresh_token, path=COOKIE_PATH,
max_age=refresh_token_max_age, secure=True, httponly=True)
response.set_cookie(key="spotRefreshToken", value=spot_refresh_token, path=spot.COOKIE_PATH,
max_age=spot_refresh_token_max_age, secure=True, httponly=True)
return data
@public_app.post('/login', tags=["authentication"])
def login_user(response: JSONResponse, spot: Optional[bool] = False, data: schemas.UserLoginSchema = Body(...)):
def login_user(response: JSONResponse, data: schemas.UserLoginSchema = Body(...)):
if helper.allow_captcha() and not captcha.is_valid(data.g_recaptcha_response):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid captcha."
)
r = users.authenticate(email=data.email, password=data.password.get_secret_value(), include_spot=spot)
r = users.authenticate(email=data.email, password=data.password.get_secret_value())
if r is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
@ -69,26 +91,8 @@ def login_user(response: JSONResponse, spot: Optional[bool] = False, data: schem
status_code=status.HTTP_401_UNAUTHORIZED,
detail=r["errors"][0]
)
r["smtp"] = smtp.has_smtp()
refresh_token = r.pop("refreshToken")
refresh_token_max_age = r.pop("refreshTokenMaxAge")
content = {
'jwt': r.pop('jwt'),
'data': {
"user": r,
"scopeState": scope.get_scope(-1)
}
}
response.set_cookie(key="refreshToken", value=refresh_token, path=COOKIE_PATH,
max_age=refresh_token_max_age, secure=True, httponly=True)
if spot:
content["spotJwt"] = r.pop("spotJwt")
spot_refresh_token = r.pop("spotRefreshToken")
spot_refresh_token_max_age = r.pop("spotRefreshTokenMaxAge")
response.set_cookie(key="spotRefreshToken", value=spot_refresh_token, path="/api/spot/refresh",
max_age=spot_refresh_token_max_age, secure=True, httponly=True)
return content
r = __process_authentication_response(response=response, data=r)
return r
@app.get('/logout', tags=["login"])
@ -125,6 +129,7 @@ def get_account(context: schemas.CurrentContext = Depends(OR_context)):
**r,
**t,
**license.get_status(context.tenant_id),
"settings": users.get_user_settings(context.user_id)["settings"],
"smtp": smtp.has_smtp()
}
}
@ -197,7 +202,7 @@ def process_invitation_link(token: str):
@public_app.post('/password/reset', tags=["users"])
def change_password_by_invitation(data: schemas.EditPasswordByInvitationSchema = Body(...)):
def change_password_by_invitation(response: JSONResponse, data: schemas.EditPasswordByInvitationSchema = Body(...)):
if data is None or len(data.invitation) < 64 or len(data.passphrase) < 8:
return {"errors": ["please provide a valid invitation & pass"]}
user = users.get_by_invitation_token(token=data.invitation, pass_token=data.passphrase)
@ -206,7 +211,9 @@ def change_password_by_invitation(data: schemas.EditPasswordByInvitationSchema =
if user["expiredChange"]:
return {"errors": ["expired change, please re-use the invitation link"]}
return users.set_password_invitation(new_password=data.password.get_secret_value(), user_id=user["userId"])
r = users.set_password_invitation(new_password=data.password.get_secret_value(), user_id=user["userId"])
r = __process_authentication_response(response=response, data=r)
return r
@app.put('/client/members/{memberId}', tags=["client"], dependencies=[OR_role("owner", "admin")])

View file

@ -8,10 +8,9 @@ from pydantic import BaseModel
from starlette import status
import schemas
from chalicelib.core import authorizers, metadata, projects
from chalicelib.core import roles, spot
from chalicelib.core import tenants, assist
from chalicelib.utils import email_helper, smtp
from chalicelib.core import authorizers, metadata
from chalicelib.core import tenants, roles, spot, scope
from chalicelib.utils import email_helper
from chalicelib.utils import helper
from chalicelib.utils import pg_client
from chalicelib.utils.TimeUTC import TimeUTC
@ -541,16 +540,16 @@ def set_password_invitation(tenant_id, user_id, new_password):
"projects": -1,
"metadata": metadata.get_remaining_metadata_with_count(tenant_id)}
c = tenants.get_by_tenant_id(tenant_id)
c.pop("createdAt")
c["projects"] = projects.get_projects(tenant_id=tenant_id, recorded=True, user_id=user_id)
c["smtp"] = smtp.has_smtp()
c["iceServers"] = assist.get_ice_servers()
return {
'jwt': r.pop('jwt'),
"jwt": r.pop("jwt"),
"refreshToken": r.pop("refreshToken"),
"refreshTokenMaxAge": r.pop("refreshTokenMaxAge"),
"spotJwt": r.pop("spotJwt"),
"spotRefreshToken": r.pop("spotRefreshToken"),
"spotRefreshTokenMaxAge": r.pop("spotRefreshTokenMaxAge"),
'data': {
"user": r,
"client": c
"scopeState": scope.get_scope(r["tenantId"]),
"user": r
}
}
@ -652,32 +651,27 @@ class ChangeJwt(BaseModel):
jwt_iat: int
jwt_refresh_jti: int
jwt_refresh_iat: int
spot_jwt_iat: int | None = None
spot_jwt_refresh_jti: int | None = None
spot_jwt_refresh_iat: int | None = None
spot_jwt_iat: int
spot_jwt_refresh_jti: int
spot_jwt_refresh_iat: int
def change_jwt_iat_jti(user_id, include_spot: bool = False):
sub_query = ""
sub_result = ""
if include_spot:
sub_query = """,spot_jwt_iat = timezone('utc'::text, now()-INTERVAL '10s'),
spot_jwt_refresh_jti = 0,
spot_jwt_refresh_iat = timezone('utc'::text, now()-INTERVAL '10s')"""
sub_result = """,EXTRACT (epoch FROM spot_jwt_iat)::BIGINT AS spot_jwt_iat,
spot_jwt_refresh_jti,
EXTRACT (epoch FROM spot_jwt_refresh_iat)::BIGINT AS spot_jwt_refresh_iat"""
def change_jwt_iat_jti(user_id):
with pg_client.PostgresClient() as cur:
query = cur.mogrify(f"""UPDATE public.users
SET jwt_iat = timezone('utc'::text, now()-INTERVAL '10s'),
jwt_refresh_jti = 0,
jwt_refresh_iat = timezone('utc'::text, now()-INTERVAL '10s')
{sub_query}
jwt_refresh_iat = timezone('utc'::text, now()-INTERVAL '10s'),
spot_jwt_iat = timezone('utc'::text, now()-INTERVAL '10s'),
spot_jwt_refresh_jti = 0,
spot_jwt_refresh_iat = timezone('utc'::text, now()-INTERVAL '10s')
WHERE user_id = %(user_id)s
RETURNING EXTRACT (epoch FROM jwt_iat)::BIGINT AS jwt_iat,
jwt_refresh_jti,
EXTRACT (epoch FROM jwt_refresh_iat)::BIGINT AS jwt_refresh_iat
{sub_result};""",
EXTRACT (epoch FROM jwt_refresh_iat)::BIGINT AS jwt_refresh_iat,
EXTRACT (epoch FROM spot_jwt_iat)::BIGINT AS spot_jwt_iat,
spot_jwt_refresh_jti,
EXTRACT (epoch FROM spot_jwt_refresh_iat)::BIGINT AS spot_jwt_refresh_iat;""",
{"user_id": user_id})
cur.execute(query)
row = cur.fetchone()
@ -699,7 +693,9 @@ def refresh_jwt_iat_jti(user_id):
return row.get("jwt_iat"), row.get("jwt_refresh_jti"), row.get("jwt_refresh_iat")
def authenticate(email, password, for_change_password=False, include_spot=False) -> dict | bool | None:
def authenticate(email, password, for_change_password=False) -> dict | bool | None:
if config("enforce_SSO", cast=bool, default=False) and helper.is_saml2_available():
return {"errors": ["must sign-in with SSO, enforced by admin"]}
with pg_client.PostgresClient() as cur:
query = cur.mogrify(
f"""SELECT
@ -749,7 +745,7 @@ def authenticate(email, password, for_change_password=False, include_spot=False)
elif config("enforce_SSO", cast=bool, default=False) and helper.is_saml2_available():
return {"errors": ["must sign-in with SSO, enforced by admin"]}
j_r = change_jwt_iat_jti(user_id=r['userId'], include_spot=include_spot)
j_r = change_jwt_iat_jti(user_id=r['userId'])
response = {
"jwt": authorizers.generate_jwt(user_id=r['userId'], tenant_id=r['tenantId'], iat=j_r.jwt_iat,
aud=AUDIENCE),
@ -758,23 +754,19 @@ def authenticate(email, password, for_change_password=False, include_spot=False)
jwt_jti=j_r.jwt_refresh_jti),
"refreshTokenMaxAge": config("JWT_REFRESH_EXPIRATION", cast=int),
"email": email,
"spotJwt": authorizers.generate_jwt(user_id=r['userId'], tenant_id=r['tenantId'],
iat=j_r.spot_jwt_iat, aud=spot.AUDIENCE, for_spot=True),
"spotRefreshToken": authorizers.generate_jwt_refresh(user_id=r['userId'],
tenant_id=r['tenantId'],
iat=j_r.spot_jwt_refresh_iat,
aud=spot.AUDIENCE,
jwt_jti=j_r.spot_jwt_refresh_jti,
for_spot=True),
"spotRefreshTokenMaxAge": config("JWT_SPOT_REFRESH_EXPIRATION", cast=int),
**r
}
if include_spot:
response = {**response,
"spotJwt": authorizers.generate_jwt(user_id=r['userId'], tenant_id=r['tenantId'],
iat=j_r.spot_jwt_iat, aud=spot.AUDIENCE, for_spot=True),
"spotRefreshToken": authorizers.generate_jwt_refresh(user_id=r['userId'],
tenant_id=r['tenantId'],
iat=j_r.spot_jwt_refresh_iat,
aud=spot.AUDIENCE,
jwt_jti=j_r.spot_jwt_refresh_jti,
for_spot=True),
"spotRefreshTokenMaxAge": config("JWT_SPOT_REFRESH_EXPIRATION", cast=int),
}
return response
if config("enforce_SSO", cast=bool, default=False) and helper.is_saml2_available():
return {"errors": ["must sign-in with SSO, enforced by admin"]}
return None
@ -865,7 +857,7 @@ def refresh(user_id: int, tenant_id: int) -> dict:
}
def authenticate_sso(email: str, internal_id: str, include_spot: bool = False):
def authenticate_sso(email: str, internal_id: str):
with pg_client.PostgresClient() as cur:
query = cur.mogrify(
f"""SELECT
@ -891,27 +883,23 @@ def authenticate_sso(email: str, internal_id: str, include_spot: bool = False):
if r["serviceAccount"]:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
detail="service account is not authorized to login")
j_r = change_jwt_iat_jti(user_id=r['userId'], include_spot=include_spot)
j_r = change_jwt_iat_jti(user_id=r['userId'])
response = {
"jwt": authorizers.generate_jwt(user_id=r['userId'], tenant_id=r['tenantId'], iat=j_r.jwt_iat,
aud=AUDIENCE),
"refreshToken": authorizers.generate_jwt_refresh(user_id=r['userId'], tenant_id=r['tenantId'],
iat=j_r.jwt_refresh_iat,
aud=AUDIENCE, jwt_jti=j_r.jwt_refresh_jti),
"refreshTokenMaxAge": config("JWT_REFRESH_EXPIRATION", cast=int)
"refreshTokenMaxAge": config("JWT_REFRESH_EXPIRATION", cast=int),
"spotJwt": authorizers.generate_jwt(user_id=r['userId'], tenant_id=r['tenantId'],
iat=j_r.spot_jwt_iat, aud=spot.AUDIENCE),
"spotRefreshToken": authorizers.generate_jwt_refresh(user_id=r['userId'],
tenant_id=r['tenantId'],
iat=j_r.spot_jwt_refresh_iat,
aud=spot.AUDIENCE,
jwt_jti=j_r.spot_jwt_refresh_jti),
"spotRefreshTokenMaxAge": config("JWT_SPOT_REFRESH_EXPIRATION", cast=int)
}
if include_spot:
response = {
**response,
"spotJwt": authorizers.generate_jwt(user_id=r['userId'], tenant_id=r['tenantId'],
iat=j_r.spot_jwt_iat, aud=spot.AUDIENCE),
"spotRefreshToken": authorizers.generate_jwt_refresh(user_id=r['userId'],
tenant_id=r['tenantId'],
iat=j_r.spot_jwt_refresh_iat,
aud=spot.AUDIENCE,
jwt_jti=j_r.spot_jwt_refresh_jti),
"spotRefreshTokenMaxAge": config("JWT_SPOT_REFRESH_EXPIRATION", cast=int)
}
return response
logger.warning(f"SSO user not found with email: {email} and internal_id: {internal_id}")
return None

View file

@ -15,13 +15,13 @@ from chalicelib.core import tenants, users, projects, license
from chalicelib.core import unprocessed_sessions
from chalicelib.core import webhook
from chalicelib.core.collaboration_slack import Slack
from chalicelib.core.users import get_user_settings
from chalicelib.utils import SAML2_helper, smtp
from chalicelib.utils import captcha
from chalicelib.utils import helper
from chalicelib.utils.TimeUTC import TimeUTC
from or_dependencies import OR_context, OR_scope, OR_role
from routers.base import get_routers
from routers.subs import spot
from schemas import Permissions, ServicePermissions
if config("ENABLE_SSO", cast=bool, default=True):
@ -55,15 +55,36 @@ if config("MULTI_TENANTS", cast=bool, default=False) or not tenants.tenants_exis
return content
def __process_authentication_response(response: JSONResponse, data: dict) -> dict:
data["smtp"] = smtp.has_smtp()
refresh_token = data.pop("refreshToken")
refresh_token_max_age = data.pop("refreshTokenMaxAge")
spot_refresh_token = data.pop("spotRefreshToken")
spot_refresh_token_max_age = data.pop("spotRefreshTokenMaxAge")
data = {
'jwt': data.pop('jwt'),
"spotJwt": data.pop("spotJwt"),
'data': {
"scopeState": scope.get_scope(data["tenantId"]),
"user": data
}
}
response.set_cookie(key="refreshToken", value=refresh_token, path=COOKIE_PATH,
max_age=refresh_token_max_age, secure=True, httponly=True)
response.set_cookie(key="spotRefreshToken", value=spot_refresh_token, path=spot.COOKIE_PATH,
max_age=spot_refresh_token_max_age, secure=True, httponly=True)
return data
@public_app.post('/login', tags=["authentication"])
def login_user(response: JSONResponse, spot: Optional[bool] = False, data: schemas.UserLoginSchema = Body(...)):
def login_user(response: JSONResponse, data: schemas.UserLoginSchema = Body(...)):
if helper.allow_captcha() and not captcha.is_valid(data.g_recaptcha_response):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid captcha."
)
r = users.authenticate(email=data.email, password=data.password.get_secret_value(), include_spot=spot)
r = users.authenticate(email=data.email, password=data.password.get_secret_value())
if r is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
@ -74,26 +95,8 @@ def login_user(response: JSONResponse, spot: Optional[bool] = False, data: schem
status_code=status.HTTP_401_UNAUTHORIZED,
detail=r["errors"][0]
)
r["smtp"] = smtp.has_smtp()
refresh_token = r.pop("refreshToken")
refresh_token_max_age = r.pop("refreshTokenMaxAge")
content = {
'jwt': r.pop('jwt'),
'data': {
"scopeState": scope.get_scope(r["tenantId"]),
"user": r
}
}
response.set_cookie(key="refreshToken", value=refresh_token, path=COOKIE_PATH,
max_age=refresh_token_max_age, secure=True, httponly=True)
if spot:
content["spotJwt"] = r.pop("spotJwt")
spot_refresh_token = r.pop("spotRefreshToken")
spot_refresh_token_max_age = r.pop("spotRefreshTokenMaxAge")
response.set_cookie(key="spotRefreshToken", value=spot_refresh_token, path="/api/spot/refresh",
max_age=spot_refresh_token_max_age, secure=True, httponly=True)
return content
r = __process_authentication_response(response=response, data=r)
return r
@app.get('/logout', tags=["login"])
@ -105,13 +108,12 @@ def logout_user(response: Response, context: schemas.CurrentContext = Depends(OR
@app.get('/refresh', tags=["login"])
def refresh_login(context: schemas.CurrentContext = Depends(OR_context)):
def refresh_login(response: JSONResponse, context: schemas.CurrentContext = Depends(OR_context)):
r = users.refresh(user_id=context.user_id, tenant_id=context.tenant_id)
content = {"jwt": r.get("jwt")}
response = JSONResponse(content=content)
response.set_cookie(key="refreshToken", value=r.get("refreshToken"), path=COOKIE_PATH,
max_age=r.pop("refreshTokenMaxAge"), secure=True, httponly=True)
return response
return content
@app.get('/account', tags=['accounts'])
@ -131,7 +133,7 @@ def get_account(context: schemas.CurrentContext = Depends(OR_context)):
**r,
**t,
**license.get_status(context.tenant_id),
"settings": get_user_settings(context.user_id)["settings"],
"settings": users.get_user_settings(context.user_id)["settings"],
"smtp": smtp.has_smtp(),
"saml2": SAML2_helper.is_saml2_available()
}
@ -207,7 +209,7 @@ async def process_invitation_link(token: str, request: Request):
@public_app.post('/password/reset', tags=["users"])
def change_password_by_invitation(data: schemas.EditPasswordByInvitationSchema = Body(...)):
def change_password_by_invitation(response: JSONResponse, data: schemas.EditPasswordByInvitationSchema = Body(...)):
if data is None or len(data.invitation) < 64 or len(data.passphrase) < 8:
return {"errors": ["please provide a valid invitation & pass"]}
user = users.get_by_invitation_token(token=data.invitation, pass_token=data.passphrase)
@ -216,8 +218,10 @@ def change_password_by_invitation(data: schemas.EditPasswordByInvitationSchema =
if user["expiredChange"]:
return {"errors": ["expired change, please re-use the invitation link"]}
return users.set_password_invitation(new_password=data.password.get_secret_value(), user_id=user["userId"],
tenant_id=user["tenantId"])
r = users.set_password_invitation(new_password=data.password.get_secret_value(), user_id=user["userId"],
tenant_id=user["tenantId"])
r = __process_authentication_response(response=response, data=r)
return r
@app.put('/client/members/{memberId}', tags=["client"], dependencies=[OR_role("owner", "admin")])

View file

@ -8,7 +8,9 @@ from starlette.responses import RedirectResponse
from chalicelib.core import users, tenants, roles
from chalicelib.utils import SAML2_helper
from routers import core_dynamic
from routers.base import get_routers
from routers.subs import spot
logger = logging.getLogger(__name__)
@ -17,11 +19,11 @@ public_app, app, app_apikey = get_routers(prefix="/sso/saml2")
@public_app.get("", tags=["saml2"])
@public_app.get("/", tags=["saml2"])
async def start_sso(request: Request, iFrame: bool = False, spot: bool = False):
async def start_sso(request: Request, iFrame: bool = False):
request.path = ''
req = await SAML2_helper.prepare_request(request=request)
auth = SAML2_helper.init_saml_auth(req)
sso_built_url = auth.login(return_to=json.dumps({'iFrame': iFrame, 'spot': spot}))
sso_built_url = auth.login(return_to=json.dumps({'iFrame': iFrame}))
return RedirectResponse(url=sso_built_url)
@ -42,7 +44,6 @@ async def __process_assertion(request: Request, tenant_key=None) -> Response | d
post_data = {}
redirect_to_link2 = None
spot = False
relay_state = post_data.get('RelayState')
if relay_state:
if isinstance(relay_state, str):
@ -53,7 +54,6 @@ async def __process_assertion(request: Request, tenant_key=None) -> Response | d
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:
@ -153,17 +153,15 @@ async def __process_assertion(request: Request, tenant_key=None) -> Response | d
logger.info(f"== Updating user:{existing['userId']}: {to_update} ==")
users.update(tenant_id=t['tenantId'], user_id=existing["userId"], changes=to_update)
jwt = users.authenticate_sso(email=email, internal_id=internal_id, include_spot=spot)
jwt = users.authenticate_sso(email=email, internal_id=internal_id)
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",
response.set_cookie(key="refreshToken", value=jwt["refreshToken"], path=core_dynamic.COOKIE_PATH,
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)
query_params["spotJwt"] = jwt["spotJwt"]
query_params = {"jwt": jwt["jwt"], "spotJwt": jwt["spotJwt"]}
response.set_cookie(key="spotRefreshToken", value=jwt["spotRefreshToken"], path=spot.COOKIE_PATH,
max_age=jwt["spotRefreshTokenMaxAge"], secure=True, httponly=True)
headers = {'Location': SAML2_helper.get_landing_URL(query_params=query_params, redirect_to_link2=redirect_to_link2)}
response.init_headers(headers)