Skip to content

Commit

Permalink
Fix the tests for authlib change
Browse files Browse the repository at this point in the history
Removes social_auth_sqlalchemy references as the social_auth tables are
no longer needed with authlib.
All tests are now passing.

Signed-off-by: Michal Konecny <[email protected]>
  • Loading branch information
Zlopez committed Nov 27, 2024
1 parent 6702b3c commit 15f34ce
Show file tree
Hide file tree
Showing 17 changed files with 1,576 additions and 1,988 deletions.
8 changes: 0 additions & 8 deletions anitya/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

import flask
from dateutil import parser
from social_flask_sqlalchemy import models as social_models
from sqlalchemy.orm.exc import NoResultFound

import anitya
Expand Down Expand Up @@ -678,13 +677,6 @@ def delete_user(user_id):

if form.validate_on_submit():
if confirm:
social_auth_records = (
Session.query(social_models.UserSocialAuth)
.filter_by(user_id=user_id)
.all()
)
for record in social_auth_records:
Session.delete(record)
Session.delete(user)
Session.commit()
flask.flash(f"User {user_name} has been removed", "success")
Expand Down
87 changes: 3 additions & 84 deletions anitya/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,20 @@
import logging.handlers

import flask
from flask_login import LoginManager, current_user, user_logged_in
from flask import url_for, render_template
from authlib.integrations.flask_client import OAuth
from flask_login import LoginManager, current_user, user_logged_in
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm.exc import NoResultFound

<<<<<<< HEAD
=======
from anitya.config import config as anitya_config
from anitya.db import Session, initialize as initialize_db, models
from anitya.lib import utilities
from . import ui, admin, api, api_v2, authentication, auth
>>>>>>> ffbba79 (Migrate social_auth to authlib)
import anitya.lib
import anitya.mail_logging
from anitya import __version__
from anitya import __version__, admin, api, api_v2, auth, authentication, ui
from anitya.config import config as anitya_config
from anitya.db import Session
from anitya.db import initialize as initialize_db
from anitya.db import models
from anitya.lib import utilities

from . import admin, api, api_v2, authentication, ui


def create(config=None):
"""
Expand Down Expand Up @@ -93,13 +83,10 @@ def create(config=None):
app.teardown_request(shutdown_session)
app.register_error_handler(IntegrityError, integrity_error_handler)
# TODO: Need to change for authlib
#app.register_error_handler(AuthException, auth_error_handler)
# app.register_error_handler(AuthException, auth_error_handler)

app.context_processor(inject_variable)

# subscribe to signals
user_logged_in.connect(when_user_log_in, app)

if app.config.get("EMAIL_ERRORS"):
# If email logging is configured, set up the anitya logger with an email
# handler for any ERROR-level logs.
Expand Down Expand Up @@ -154,72 +141,4 @@ def integrity_error_handler(error):
Returns:
tuple: A tuple of (message, HTTP error code).
"""
# Because social auth provides the route and raises the exception, this is
# the simplest way to turn the error into a nicely formatted error message
# for the user.
if "email" in error.params:
Session.rollback()
other_user = models.User.query.filter_by(email=error.params["email"]).one()
try:
social_auth_user = other_user.oauth.filter_by(
user_id=other_user.id
).one()
msg = (
"Error: There's already an account associated with your email, "
f"authenticate with {social_auth_user.provider}."
)
return msg, 400
# This error happens only if there is account without provider info
except NoResultFound:
Session.delete(other_user)
Session.commit()
msg = (
"Error: There was already an existing account with missing provider. "
"So we removed it. "
"Please try to log in again."
)
return msg, 500

return "The server encountered an unexpected error", 500


def auth_error_handler(error):
"""
Flask error handler for unhandled AuthException errors.
Args:
error (AuthException): The exception to be handled.
Returns:
tuple: A tuple of (message, HTTP error code).
"""
# Because social auth openId backend provides route and raises the exceptions,
# this is the simplest way to turn error into nicely formatted error message.
msg = (
f"Error: There was an error during authentication '{error}', "
"please check the provided url."
)
return msg, 400


def when_user_log_in(sender, user):
"""
This catches the signal when user is logged in.
It checks if the user has associated entry in user_social_auth.
Args:
sender (flask.Flask): Current app object that emitted signal.
Not used by this method.
user (models.User): User that is logging in.
Raises:
sqlalchemy.exc.IntegrityError: When user_social_auth table entry is
missing.
"""
# TODO: new social table need to be added
#if user.oauth.count() == 0:
# raise IntegrityError(
# "Missing authlib table",
# {"authlib": None, "email": user.email},
# None,
# )
34 changes: 17 additions & 17 deletions anitya/auth.py
Original file line number Diff line number Diff line change
@@ -1,59 +1,59 @@
import flask
import flask_login

from anitya.db import User, Session
from anitya.db import Session, User


def create_oauth_blueprint(oauth):
oauth_blueprint = flask.Blueprint('oauth', __name__)
oauth_blueprint = flask.Blueprint("oauth", __name__)

@oauth_blueprint.route("/oauthlogin/<name>")
def oauthlogin(name):
client = oauth.create_client(name)
if client is None:
flask.abort(400)
redirect_uri = flask.url_for('.auth', name=name, _external=True)
redirect_uri = flask.url_for(".auth", name=name, _external=True)
return client.authorize_redirect(redirect_uri)


@oauth_blueprint.route("/auth/<name>")
def auth(name):
client = oauth.create_client(name)
if client is None:
flask.abort(400)
id_token = flask.request.values.get('id_token')
if flask.request.values.get('code'):
id_token = flask.request.values.get("id_token")
if flask.request.values.get("code"):
token = client.authorize_access_token()
if id_token:
token['id_token'] = id_token
token["id_token"] = id_token
elif id_token:
token = {'id_token': id_token}
token = {"id_token": id_token}

# for Google
if 'id_token' in token:
if "id_token" in token:
user_info = client.parse_id_token(token)
# for Github
else:
client.response = client.get('user', token=token)
client.response = client.get("user", token=token)
user_info = client.response.json()
if user_info['email'] is None:
resp = client.get('user/emails', token=token)
if user_info["email"] is None:
resp = client.get("user/emails", token=token)
resp.raise_for_status()
data = resp.json()
user_info['email'] = next(email['email'] for email in data if email['primary'])
user_info["email"] = next(
email["email"] for email in data if email["primary"]
)

# Check if the user exists
user = User.query.filter(User.email == user_info['email']).first()
user = User.query.filter(User.email == user_info["email"]).first()
if not user:

# TODO: Should create the user (and openid connections) if it does not exist
new_user = User(email=user_info['email'], username=user_info['email'])
new_user = User(email=user_info["email"], username=user_info["email"])
Session.add(new_user)
Session.commit()
user = new_user
flask_login.login_user(user)

# TODO: Process next not to just redirect with the main page
return flask.redirect('/')
return flask.redirect("/")

return oauth_blueprint
32 changes: 9 additions & 23 deletions anitya/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,6 @@
EMAIL_ERRORS=False,
BLACKLISTED_USERS=[],
SESSION_PROTECTION="strong",
SOCIAL_AUTH_AUTHENTICATION_BACKENDS=(
"social_core.backends.fedora.FedoraOpenId",
"social_core.backends.gitlab.GitLabOAuth2",
"social_core.backends.github.GithubOAuth2",
"social_core.backends.google.GoogleOAuth2",
"social_core.backends.open_id.OpenIdAuth",
),
SOCIAL_AUTH_STORAGE="social_flask_sqlalchemy.models.FlaskStorage",
SOCIAL_AUTH_USER_MODEL="anitya.db.models.User",
# Force the application to require HTTPS on authentication redirects.
SOCIAL_AUTH_REDIRECT_IS_HTTPS=True,
SOCIAL_AUTH_LOGIN_URL="/login/",
SOCIAL_AUTH_LOGIN_REDIRECT_URL="/",
SOCIAL_AUTH_LOGIN_ERROR_URL="/login-error/",
DEFAULT_REGEX=r"(?i)%(name)s(?:[-_]?(?:minsrc|src|source))?[-_]([^-/_\s]+?(?:[-_]"
r"(?:rc|devel|dev|alpha|beta)\d+)?)(?:[-_](?:minsrc|src|source|asc|release))?"
r"\.(?:tar|t[bglx]z|tbz2|zip)",
Expand All @@ -91,16 +77,16 @@
CHECK_ERROR_THRESHOLD=100,
DISTRO_MAPPING_LINKS={},
# Enabled authentication backends
AUTHLIB_ENABLED_BACKENDS=['Fedora', 'GitHub', 'Google'],
AUTHLIB_ENABLED_BACKENDS=["Fedora", "GitHub", "Google"],
# Token for GitHub API
GITHUB_ACCESS_TOKEN_URL='https://github.com/login/oauth/access_token',
GITHUB_AUTHORIZE_URL='https://github.com/login/oauth/authorize',
GITHUB_API_BASE_URL='https://api.github.com/',
GITHUB_CLIENT_KWARGS={'scope': 'user:email'},
FEDORA_CLIENT_KWARGS={'scope': 'openid email profile'},
FEDORA_SERVER_METADATA_URL='https://id.fedoraproject.org/.well-known/openid-configuration',
GOOGLE_CLIENT_KWARGS={'scope': 'openid email profile'},
GOOGLE_SERVER_METADATA_URL='https://accounts.google.com/.well-known/openid-configuration',
GITHUB_ACCESS_TOKEN_URL="https://github.com/login/oauth/access_token",
GITHUB_AUTHORIZE_URL="https://github.com/login/oauth/authorize",
GITHUB_API_BASE_URL="https://api.github.com/",
GITHUB_CLIENT_KWARGS={"scope": "user:email"},
FEDORA_CLIENT_KWARGS={"scope": "openid email profile"},
FEDORA_SERVER_METADATA_URL="https://id.fedoraproject.org/.well-known/openid-configuration",
GOOGLE_CLIENT_KWARGS={"scope": "openid email profile"},
GOOGLE_SERVER_METADATA_URL="https://accounts.google.com/.well-known/openid-configuration",
)

# Start with a basic logging configuration, which will be replaced by any user-
Expand Down
2 changes: 0 additions & 2 deletions anitya/db/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -977,8 +977,6 @@ class User(Base):
able to log in.
admin (bool): Determine if this user is an administrator. If True the user is
administrator.
social_auth (sqlalchemy.orm.dynamic.AppenderQuery): The list of
:class:`social_flask_sqlalchemy.models.UserSocialAuth` entries for this user.
"""

__tablename__ = "users"
Expand Down
20 changes: 0 additions & 20 deletions anitya/sar.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,26 +65,6 @@ def main():
users_list = []
for user in users:
user_dict = user.to_dict()
user_social_auths = db.Session.execute(
select(
text(
"provider,extra_data,uid FROM social_auth_usersocialauth WHERE user_id = :val"
)
),
{"val": str(user.id)},
)
user_dict["user_social_auths"] = []
# This part is working in postgresql, but in tests we are using sqlite
# which doesn't know the UUID type
# pylint: disable=not-an-iterable
for user_social_auth in user_social_auths: # pragma: no cover
user_dict["user_social_auths"].append(
{
"provider": user_social_auth["provider"],
"extra_data": user_social_auth["extra_data"],
"uid": user_social_auth["uid"],
}
)
users_list.append(user_dict)

json.dump(users_list, sys.stdout)
Expand Down
2 changes: 0 additions & 2 deletions anitya/tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import flask_login
import vcr
from flask import request_started
from social_flask_sqlalchemy.models import PSABase
from sqlalchemy import create_engine, event

from anitya import app, config
Expand Down Expand Up @@ -146,7 +145,6 @@ def setUp(self):

self.connection = engine.connect()
Base.metadata.create_all(bind=self.connection)
PSABase.metadata.create_all(bind=self.connection)
self.transaction = self.connection.begin_nested()

Session.remove()
Expand Down
Loading

0 comments on commit 15f34ce

Please sign in to comment.