Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion source/app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def ac_current_user_has_manage_perms():
]}})


app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1)
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_port=1)
#app.wsgi_app = store.wsgi_middleware(app.wsgi_app)

socket_io = SocketIO(app, cors_allowed_origins="*")
Expand Down
66 changes: 49 additions & 17 deletions source/app/blueprints/pages/login/login_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,25 @@ def oidc_login():
session["oidc_state"] = rndstr()
session["oidc_nonce"] = rndstr()

xf_proto = request.headers.get("X-Forwarded-Proto")
xf_host = request.headers.get("X-Forwarded-Host")

if xf_proto:
xf_proto = xf_proto.split(",")[0].strip()
if xf_host:
xf_host = xf_host.split(",")[0].strip()

redirect_uri = url_for("login.oidc_authorise", _external=True)

if xf_proto and xf_host:
redirect_uri = f"{xf_proto}://{xf_host}/oidc-authorize"

args = {
"client_id": oidc_client.client_id,
"response_type": "code",
"scope": app.config.get("OIDC_SCOPES"),
"nonce": session["oidc_nonce"],
"redirect_uri": url_for("login.oidc_authorise", _external=True),
"redirect_uri": redirect_uri,
"state": session["oidc_state"],
}

Expand Down Expand Up @@ -212,6 +225,18 @@ def oidc_authorise():
"code": auth_resp["code"],
}

xf_proto = request.headers.get("X-Forwarded-Proto")
xf_host = request.headers.get("X-Forwarded-Host")

if xf_proto:
xf_proto = xf_proto.split(",")[0].strip()
if xf_host:
xf_host = xf_host.split(",")[0].strip()

if xf_proto and xf_host:
public_base = f"{xf_proto}://{xf_host}"
args["redirect_uri"] = f"{public_base}/oidc-authorize"

access_token_resp = oidc_client.do_access_token_request(
state=auth_resp["state"], request_args=args
)
Expand All @@ -223,25 +248,32 @@ def oidc_authorise():
usergroup_field = app.config.get("OIDC_MAPPING_USERGROUP")
userroles_mapping_field = app.config.get("OIDC_MAPPING_ROLES")
try:
if "id_token" not in access_token_resp:
log.error(
"OIDC authentication failed: 'id_token' not found in access token response"
)
track_activity(
"OIDC authentication failed: missing id_token in response",
ctx_less=True,
display_in_ui=False,
if "id_token" in access_token_resp and access_token_resp["id_token"]:
claims = access_token_resp["id_token"]
else:
if "access_token" not in access_token_resp:
err = access_token_resp.get("error")
desc = access_token_resp.get("error_description")
log.error(
f"OIDC authentication failed: token response missing access_token (error={err}, desc={desc})"
)
track_activity(
f"OIDC authentication failed: token response missing access_token (error={err}, desc={desc})",
ctx_less=True,
display_in_ui=False,
)
return redirect(url_for("login.login"))

claims = oidc_client.do_user_info_request(
state=auth_resp["state"],
access_token=access_token_resp["access_token"],
)
return redirect(url_for("login.login"))

user_login = access_token_resp["id_token"].get(
username_field
) or access_token_resp["id_token"].get(email_field)
user_name = access_token_resp["id_token"].get(
email_field
) or access_token_resp["id_token"].get(username_field)
user_login = claims.get(username_field) or claims.get(email_field)
user_name = claims.get(email_field) or claims.get(username_field)

if usergroup_field is not None:
user_group = access_token_resp["id_token"].get(usergroup_field)
user_group = claims.get(usergroup_field)
else:
user_group = None

Expand Down
22 changes: 22 additions & 0 deletions source/app/blueprints/rest/v2/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,28 @@ def login():
return response_api_success(data=user_data)


@auth_blueprint.get('/whoami')
def whoami():
"""
Returns current authenticated user info (based on the existing session) and API tokens.
Output shape matches the frontend's existing local-login handler:
{ responseData, tokenInfo, redirectTo }
"""
if not iris_current_user.is_authenticated:
return response_api_error('Unauthorized', 401)

user = users_get_active(iris_current_user.id)
response_data = UserSchema(exclude=['user_password', 'mfa_secrets', 'webauthn_credentials']).dump(user)

token_info = generate_auth_tokens(user)

return response_api_success(data={
'responseData': response_data,
'tokenInfo': token_info,
'redirectTo': '/'
})


@auth_blueprint.post('/logout')
def logout():
"""
Expand Down
Loading