Coverage for seedboxsync/front/views/auth/login.py: 87%
38 statements
« prev ^ index » next coverage.py v7.16.1, created at 2026-09-26 17:14 +0000
« prev ^ index » next coverage.py v7.16.1, created at 2026-09-26 17:14 +0000
1#
2# Copyright (C) 2015-2026 Guillaume Kulakowski <guillaume@kulakowski.fr>
3#
4# For the full copyright and license information, please view the LICENSE
5# file that was distributed with this source code.
6#
7"""SeedboxSync Flask view for authentication handling."""
9from flask import redirect, render_template, request, url_for
10from flask_login import login_user
11from werkzeug.wrappers.response import Response
12from seedboxsync.core import current_app
13from seedboxsync.core.database.models.user import User
14from seedboxsync.front.babel import gettext as _
15from seedboxsync.front.forms import LoginForm
16from seedboxsync.front.oauth2 import oauth
17from seedboxsync.front.utils import is_safe_redirect_url, toast
18from seedboxsync.front.views import bp_auth as bp
21@bp.route("/login", methods=["GET", "POST"])
22def login() -> str | Response:
23 """
24 Render and process the user login view.
26 Authenticates user credentials, logs in the user session upon successful
27 validation, and redirects to the requested target URL or homepage.
29 Returns:
30 str | Response: Rendered login template or HTTP redirect response.
31 """
32 # Auto redirect to OAuth2 provider if OAuth is enabled and built-in authentication is disabled
33 oauth_builtin_authentication_disabled = current_app.seedboxsync_config.get("oauth_builtin_authentication_disabled", False)
34 oauth_enabled = current_app.seedboxsync_config.get("oauth_enabled", False)
35 if oauth_builtin_authentication_disabled and oauth_enabled:
36 return __authorize_redirect()
38 if request.args.get("provider") == "oauth2" and current_app.seedboxsync_config.get("oauth_enabled"):
39 return __authorize_redirect()
41 form = LoginForm()
43 # Basic auth
44 if form.validate_on_submit():
45 login = request.form.get("login") or ""
46 password = request.form.get("password") or ""
47 next_url = request.args.get("next")
48 remember = request.form.get("remember") == "1"
50 user = User.authenticate(login, password)
52 # User is logged
53 if user is not None:
54 login_user(user, remember=remember)
55 toast(_("Logged in successfully."), _("Login"), "success")
57 # Sanitization/Validation for SonarQube (Open Redirect protection)
58 target_url = url_for("frontend.homepage")
59 if next_url and is_safe_redirect_url(next_url):
60 target_url = next_url
62 return redirect(target_url)
64 # User is not logged
65 toast(_("Invalid username or password."), _("Login"), "danger")
67 return render_template("login.html", form=form)
70def __authorize_redirect() -> Response:
71 """
72 Redirect the user to the configured OAuth/OIDC provider's authorization URL.
74 Obtains the registered OAuth client name from application settings, builds
75 the external redirect URI, and initiates the OIDC authorization flow.
77 Returns:
78 Response: Flask redirect response object targeting the identity provider.
79 """
80 # Retrieve OAuth client name and construct absolute callback URL
81 oauth_name = current_app.seedboxsync_config.get("oauth_name")
82 redirect_uri = url_for("auth.authorize", _external=True)
84 # Initiate authorization redirect via Authlib client
85 return oauth.create_client(oauth_name).authorize_redirect(redirect_uri) # type: ignore[no-any-return]