Respect next when logging in using GitHub

This commit is contained in:
rubenwardy 2023-10-31 18:45:24 +00:00
parent a29715775e
commit 72b608b158
4 changed files with 29 additions and 14 deletions

@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from flask import Blueprint
from flask import Blueprint, abort
from flask_babel import gettext
bp = Blueprint("github", __name__)
@ -24,13 +24,19 @@ from flask_login import current_user
from sqlalchemy import func, or_, and_
from app import github, csrf
from app.models import db, User, APIToken, Package, Permission, AuditSeverity, PackageState
from app.utils import abs_url_for, add_audit_log, login_user_set_active
from app.utils import abs_url_for, add_audit_log, login_user_set_active, is_safe_url
from app.blueprints.api.support import error, api_create_vcs_release
import hmac, requests
@bp.route("/github/start/")
def start():
return github.authorize("", redirect_uri=abs_url_for("github.callback"))
next = request.args.get("next")
if next and not is_safe_url(next):
abort(400)
return github.authorize("", redirect_uri=abs_url_for("github.callback", next=next))
@bp.route("/github/view/")
def view_permissions():
@ -46,6 +52,14 @@ def callback(oauth_token):
flash(gettext("Authorization failed [err=gh-oauth-login-failed]"), "danger")
return redirect(url_for("users.login"))
next = request.args.get("next")
if next and not is_safe_url(next):
abort(400)
redirect_to = next
if redirect_to is None:
redirect_to = url_for("homepage.home")
# Get GitGub username
url = "https://api.github.com/user"
r = requests.get(url, headers={"Authorization": "token " + oauth_token})
@ -60,10 +74,10 @@ def callback(oauth_token):
current_user.github_username = username
db.session.commit()
flash(gettext("Linked GitHub to account"), "success")
return redirect(url_for("homepage.home"))
return redirect(redirect_to)
else:
flash(gettext("GitHub account is already associated with another user"), "danger")
return redirect(url_for("homepage.home"))
return redirect(redirect_to)
# If not logged in, log in
else:
@ -71,13 +85,13 @@ def callback(oauth_token):
flash(gettext("Unable to find an account for that GitHub user"), "danger")
return redirect(url_for("users.claim_forums"))
ret = login_user_set_active(userByGithub, remember=True)
ret = login_user_set_active(userByGithub, next, remember=True)
if ret is None:
flash(gettext("Authorization failed [err=gh-login-failed]"), "danger")
return redirect(url_for("users.login"))
add_audit_log(AuditSeverity.USER, userByGithub, "Logged in using GitHub OAuth",
url_for("users.profile", username=userByGithub.username))
url_for("users.profile", username=userByGithub.username))
db.session.commit()
return ret

@ -71,11 +71,11 @@ def handle_login(form):
@bp.route("/user/login/", methods=["GET", "POST"])
def login():
if current_user.is_authenticated:
next = request.args.get("next")
if next and not is_safe_url(next):
abort(400)
next = request.args.get("next")
if next and not is_safe_url(next):
abort(400)
if current_user.is_authenticated:
return redirect(next or url_for("homepage.home"))
form = LoginForm(request.form)
@ -87,7 +87,7 @@ def login():
if request.method == "GET":
form.remember_me.data = True
return render_template("users/login.html", form=form)
return render_template("users/login.html", form=form, next=next)
@bp.route("/user/logout/", methods=["GET", "POST"])

@ -25,7 +25,7 @@
<hr class="my-5" />
<p>
<a class="btn btn-secondary me-3" href="{{ url_for('github.start') }}">
<a class="btn btn-secondary me-3" href="{{ url_for('github.start', next=next) }}">
<i class="fab fa-github me-1"></i>
{{ _("GitHub") }}
</a>

@ -16,6 +16,7 @@
from functools import wraps
from typing import Optional
from flask_babel import gettext
from flask_login import login_user, current_user
@ -57,7 +58,7 @@ def post_login(user: User, next_url):
return redirect(url_for("homepage.home"))
def login_user_set_active(user: User, next_url: str = None, *args, **kwargs):
def login_user_set_active(user: User, next_url: Optional[str] = None, *args, **kwargs):
if user.rank == UserRank.NOT_JOINED and user.email is None:
user.rank = UserRank.NEW_MEMBER
user.notification_preferences = UserNotificationPreferences(user)