Update federated login to store metadata and have the UI pull the information from the metadata

This commit is contained in:
Joseph Schorr 2014-08-11 18:25:01 -04:00
parent 2597bcef3f
commit 389c88a7c4
6 changed files with 99 additions and 30 deletions

View file

@ -11,6 +11,7 @@ from util.validation import generate_valid_usernames
from util.http import abort
from auth.permissions import AdministerRepositoryPermission
from auth.auth import require_session_login
from peewee import IntegrityError
import features
@ -22,7 +23,8 @@ client = app.config['HTTPCLIENT']
callback = Blueprint('callback', __name__)
def exchange_code_for_token(code, service_name='GITHUB', for_login=True, form_encode=False):
def exchange_code_for_token(code, service_name='GITHUB', for_login=True, form_encode=False,
redirect_suffix=''):
code = request.args.get('code')
id_config = service_name + '_LOGIN_CLIENT_ID' if for_login else service_name + '_CLIENT_ID'
secret_config = service_name + '_LOGIN_CLIENT_SECRET' if for_login else service_name + '_CLIENT_SECRET'
@ -32,9 +34,10 @@ def exchange_code_for_token(code, service_name='GITHUB', for_login=True, form_en
'client_secret': app.config[secret_config],
'code': code,
'grant_type': 'authorization_code',
'redirect_uri': '%s://%s/oauth2/%s/callback' % (app.config['PREFERRED_URL_SCHEME'],
app.config['SERVER_HOSTNAME'],
service_name.lower())
'redirect_uri': '%s://%s/oauth2/%s/callback%s' % (app.config['PREFERRED_URL_SCHEME'],
app.config['SERVER_HOSTNAME'],
service_name.lower(),
redirect_suffix)
}
headers = {
@ -74,14 +77,15 @@ def get_google_user(token):
get_user = client.get(app.config['GOOGLE_USER_URL'], params=token_param)
return get_user.json()
def conduct_oauth_login(service_name, user_id, username, email):
def conduct_oauth_login(service_name, user_id, username, email, metadata={}):
to_login = model.verify_federated_login(service_name.lower(), user_id)
if not to_login:
# try to create the user
try:
valid = next(generate_valid_usernames(username))
to_login = model.create_federated_user(valid, email, service_name.lower(),
user_id, set_password_notification=True)
user_id, set_password_notification=True,
metadata=metadata)
# Success, tell analytics
analytics.track(to_login.username, 'register', {'service': service_name.lower()})
@ -102,6 +106,15 @@ def conduct_oauth_login(service_name, user_id, username, email):
error_message='Unknown error')
def get_google_username(user_data):
username = user_data['email']
at = username.find('@')
if at > 0:
username = username[0:at]
return username
@callback.route('/google/callback', methods=['GET'])
@route_show_if(features.GOOGLE_LOGIN)
def google_oauth_callback():
@ -115,12 +128,13 @@ def google_oauth_callback():
return render_page_template('ologinerror.html', service_name = 'Google',
error_message='Could not load user data')
username = user_data['email']
at = username.find('@')
if at > 0:
username = username[0:at]
username = get_google_username(user_data)
metadata = {
'service_username': username
}
return conduct_oauth_login('Google', user_data['id'], username, user_data['email'])
return conduct_oauth_login('Google', user_data['id'], username, user_data['email'],
metadata=metadata)
@callback.route('/github/callback', methods=['GET'])
@ -156,14 +170,20 @@ def github_oauth_callback():
if user_email['primary']:
break
return conduct_oauth_login('github', github_id, username, found_email)
metadata = {
'service_username': username
}
return conduct_oauth_login('github', github_id, username, found_email, metadata=metadata)
@callback.route('/google/callback/attach', methods=['GET'])
@route_show_if(features.GOOGLE_LOGIN)
@require_session_login
def google_oauth_attach():
token = exchange_code_for_token(request.args.get('code'), service_name='GOOGLE')
token = exchange_code_for_token(request.args.get('code'), service_name='GOOGLE',
redirect_suffix='/attach', form_encode=True)
user_data = get_google_user(token)
if not user_data or not user_data.get('id', None):
return render_page_template('ologinerror.html', service_name = 'Google',
@ -171,7 +191,21 @@ def google_oauth_attach():
google_id = user_data['id']
user_obj = current_user.db_user()
model.attach_federated_login(user_obj, 'google', google_id)
username = get_google_username(user_data)
metadata = {
'service_username': username
}
try:
model.attach_federated_login(user_obj, 'google', google_id, metadata=metadata)
except IntegrityError:
err = 'Google account %s is already attached to a %s account' % (
username, app.config['REGISTRY_TITLE_SHORT'])
return render_page_template('ologinerror.html', service_name = 'Google',
error_message=err)
return redirect(url_for('web.user'))
@ -187,7 +221,21 @@ def github_oauth_attach():
github_id = user_data['id']
user_obj = current_user.db_user()
model.attach_federated_login(user_obj, 'github', github_id)
username = user_data['login']
metadata = {
'service_username': username
}
try:
model.attach_federated_login(user_obj, 'github', github_id, metadata=metadata)
except IntegrityError:
err = 'Github account %s is already attached to a %s account' % (
username, app.config['REGISTRY_TITLE_SHORT'])
return render_page_template('ologinerror.html', service_name = 'Github',
error_message=err)
return redirect(url_for('web.user'))
@ -198,7 +246,8 @@ def github_oauth_attach():
def attach_github_build_trigger(namespace, repository):
permission = AdministerRepositoryPermission(namespace, repository)
if permission.can():
token = exchange_code_for_token(request.args.get('code'), service_name='GITHUB', for_login=False)
token = exchange_code_for_token(request.args.get('code'), service_name='GITHUB',
for_login=False)
repo = model.get_repository(namespace, repository)
if not repo:
msg = 'Invalid repository: %s/%s' % (namespace, repository)