Fix for #1307 (Oauth login not working)

- Changed blueprint reference in Backend from name to id, users can now again be found
- Depending on version of flask-dance the resultcode of authorized is set different to prevent redirect loop with newer versions(>1.3)
- Redirect to login page in case no user is linked to current oauth account
- Flash messages upon successfull login, successsfull linked account
This commit is contained in:
Ozzieisaacs 2020-04-16 17:58:42 +02:00
parent a784c6bd52
commit 2c42972230
3 changed files with 29 additions and 17 deletions

View File

@ -23,12 +23,14 @@ from flask import session
try: try:
from flask_dance.consumer.backend.sqla import SQLAlchemyBackend, first, _get_real_user from flask_dance.consumer.backend.sqla import SQLAlchemyBackend, first, _get_real_user
from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.orm.exc import NoResultFound
backend_resultcode = False # prevent storing values with this resultcode
except ImportError: except ImportError:
# fails on flask-dance >1.3, due to renaming # fails on flask-dance >1.3, due to renaming
try: try:
from flask_dance.consumer.storage.sqla import SQLAlchemyStorage as SQLAlchemyBackend from flask_dance.consumer.storage.sqla import SQLAlchemyStorage as SQLAlchemyBackend
from flask_dance.consumer.storage.sqla import first, _get_real_user from flask_dance.consumer.storage.sqla import first, _get_real_user
from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.orm.exc import NoResultFound
backend_resultcode = True # prevent storing values with this resultcode
except ImportError: except ImportError:
pass pass
@ -48,7 +50,7 @@ try:
def get(self, blueprint, user=None, user_id=None): def get(self, blueprint, user=None, user_id=None):
if self.provider_id + '_oauth_token' in session and session[self.provider_id + '_oauth_token'] != '': if self.provider_id + '_oauth_token' in session and session[self.provider_id + '_oauth_token'] != '':
return session[blueprint.name + '_oauth_token'] return session[self.provider_id + '_oauth_token']
# check cache # check cache
cache_key = self.make_cache_key(blueprint=blueprint, user=user, user_id=user_id) cache_key = self.make_cache_key(blueprint=blueprint, user=user, user_id=user_id)
token = self.cache.get(cache_key) token = self.cache.get(cache_key)

View File

@ -35,7 +35,7 @@ from sqlalchemy.orm.exc import NoResultFound
from . import constants, logger, config, app, ub from . import constants, logger, config, app, ub
from .web import login_required from .web import login_required
from .oauth import OAuthBackend from .oauth import OAuthBackend, backend_resultcode
oauth_check = {} oauth_check = {}
@ -141,9 +141,9 @@ if ub.oauth_support:
scope=element['scope'] scope=element['scope']
) )
element['blueprint'] = blueprint element['blueprint'] = blueprint
app.register_blueprint(blueprint, url_prefix="/login")
element['blueprint'].backend = OAuthBackend(ub.OAuth, ub.session, str(element['id']), element['blueprint'].backend = OAuthBackend(ub.OAuth, ub.session, str(element['id']),
user=current_user, user_required=True) user=current_user, user_required=True)
app.register_blueprint(blueprint, url_prefix="/login")
if element['active']: if element['active']:
register_oauth_blueprint(element['id'], element['provider_name']) register_oauth_blueprint(element['id'], element['provider_name'])
@ -207,19 +207,23 @@ if ub.oauth_support:
ub.session.rollback() ub.session.rollback()
# Disable Flask-Dance's default behavior for saving the OAuth token # Disable Flask-Dance's default behavior for saving the OAuth token
return False # Value differrs depending on flask-dance version
return backend_resultcode
def bind_oauth_or_register(provider_id, provider_user_id, redirect_url): def bind_oauth_or_register(provider_id, provider_user_id, redirect_url, provider_name):
query = ub.session.query(ub.OAuth).filter_by( query = ub.session.query(ub.OAuth).filter_by(
provider=provider_id, provider=provider_id,
provider_user_id=provider_user_id, provider_user_id=provider_user_id,
) )
try: try:
oauth_entry = query.one() oauth_entry = query.first()
# already bind with user, just login # already bind with user, just login
if oauth_entry.user: if oauth_entry.user:
login_user(oauth_entry.user) login_user(oauth_entry.user)
log.debug(u"You are now logged in as: '%s'", oauth_entry.user.nickname)
flash(_(u"you are now logged in as: '%(nickname)s'", nickname= oauth_entry.user.nickname),
category="success")
return redirect(url_for('web.index')) return redirect(url_for('web.index'))
else: else:
# bind to current user # bind to current user
@ -228,16 +232,22 @@ if ub.oauth_support:
try: try:
ub.session.add(oauth_entry) ub.session.add(oauth_entry)
ub.session.commit() ub.session.commit()
flash(_(u"Link to %(oauth)s Succeeded", oauth=provider_name), category="success")
return redirect(url_for('web.profile'))
except Exception as e: except Exception as e:
log.exception(e) log.exception(e)
ub.session.rollback() ub.session.rollback()
return redirect(url_for('web.login')) else:
flash(_(u"Login failed, No User Linked With OAuth Account"), category="error")
log.info('Login failed, No User Linked With OAuth Account')
return redirect(url_for('web.login'))
# return redirect(url_for('web.login'))
# if config.config_public_reg: # if config.config_public_reg:
# return redirect(url_for('web.register')) # return redirect(url_for('web.register'))
# else: # else:
# flash(_(u"Public registration is not enabled"), category="error") # flash(_(u"Public registration is not enabled"), category="error")
# return redirect(url_for(redirect_url)) # return redirect(url_for(redirect_url))
except NoResultFound: except (NoResultFound, AttributeError):
return redirect(url_for(redirect_url)) return redirect(url_for(redirect_url))
@ -270,14 +280,14 @@ if ub.oauth_support:
ub.session.delete(oauth_entry) ub.session.delete(oauth_entry)
ub.session.commit() ub.session.commit()
logout_oauth_user() logout_oauth_user()
flash(_(u"Unlink to %(oauth)s success.", oauth=oauth_check[provider]), category="success") flash(_(u"Unlink to %(oauth)s Succeeded", oauth=oauth_check[provider]), category="success")
except Exception as e: except Exception as e:
log.exception(e) log.exception(e)
ub.session.rollback() ub.session.rollback()
flash(_(u"Unlink to %(oauth)s failed.", oauth=oauth_check[provider]), category="error") flash(_(u"Unlink to %(oauth)s Failed", oauth=oauth_check[provider]), category="error")
except NoResultFound: except NoResultFound:
log.warning("oauth %s for user %d not fount", provider, current_user.id) log.warning("oauth %s for user %d not found", provider, current_user.id)
flash(_(u"Not linked to %(oauth)s.", oauth=oauth_check[provider]), category="error") flash(_(u"Not Linked to %(oauth)s.", oauth=oauth_check[provider]), category="error")
return redirect(url_for('web.profile')) return redirect(url_for('web.profile'))
@ -296,7 +306,7 @@ if ub.oauth_support:
flash(msg, category="error") flash(msg, category="error")
@oauth.route('/github') @oauth.route('/link/github')
@oauth_required @oauth_required
def github_login(): def github_login():
if not github.authorized: if not github.authorized:
@ -304,7 +314,7 @@ if ub.oauth_support:
account_info = github.get('/user') account_info = github.get('/user')
if account_info.ok: if account_info.ok:
account_info_json = account_info.json() account_info_json = account_info.json()
return bind_oauth_or_register(oauthblueprints[0]['id'], account_info_json['id'], 'github.login') return bind_oauth_or_register(oauthblueprints[0]['id'], account_info_json['id'], 'github.login', 'github')
flash(_(u"GitHub Oauth error, please retry later."), category="error") flash(_(u"GitHub Oauth error, please retry later."), category="error")
return redirect(url_for('web.login')) return redirect(url_for('web.login'))
@ -315,7 +325,7 @@ if ub.oauth_support:
return unlink_oauth(oauthblueprints[0]['id']) return unlink_oauth(oauthblueprints[0]['id'])
@oauth.route('/login/google') @oauth.route('/link/google')
@oauth_required @oauth_required
def google_login(): def google_login():
if not google.authorized: if not google.authorized:
@ -323,7 +333,7 @@ if ub.oauth_support:
resp = google.get("/oauth2/v2/userinfo") resp = google.get("/oauth2/v2/userinfo")
if resp.ok: if resp.ok:
account_info_json = resp.json() account_info_json = resp.json()
return bind_oauth_or_register(oauthblueprints[1]['id'], account_info_json['id'], 'google.login') return bind_oauth_or_register(oauthblueprints[1]['id'], account_info_json['id'], 'google.login', 'google')
flash(_(u"Google Oauth error, please retry later."), category="error") flash(_(u"Google Oauth error, please retry later."), category="error")
return redirect(url_for('web.login')) return redirect(url_for('web.login'))

View File

@ -46,7 +46,7 @@
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
{% if registered_oauth.keys()| length > 0 %} {% if registered_oauth.keys()| length > 0 and not new_user %}
{% for id, name in registered_oauth.items() %} {% for id, name in registered_oauth.items() %}
<div class="form-group"> <div class="form-group">
<label>{{ name }} {{_('OAuth Settings')}}</label> <label>{{ name }} {{_('OAuth Settings')}}</label>