diff --git a/data/model.py b/data/model.py index 97414a552..7b300bedc 100644 --- a/data/model.py +++ b/data/model.py @@ -308,12 +308,18 @@ def create_federated_user(username, email, service_name, service_id): return new_user +def attach_federated_login(user, service_name, service_id): + service = LoginService.get(LoginService.name == service_name) + FederatedLogin.create(user=user, service=service, service_ident=service_id) + return user + + def verify_federated_login(service_name, service_id): selected = FederatedLogin.select(FederatedLogin, User) with_service = selected.join(LoginService) with_user = with_service.switch(FederatedLogin).join(User) found = with_user.where(FederatedLogin.service_ident == service_id, - LoginService.name == service_name) + LoginService.name == service_name) found_list = list(found) @@ -323,6 +329,14 @@ def verify_federated_login(service_name, service_id): return None +def list_federated_logins(user): + selected = FederatedLogin.select(FederatedLogin.service_ident, + LoginService.name) + joined = selected.join(LoginService) + return joined.where(LoginService.name != 'quayrobot', + FederatedLogin.user == user) + + def create_confirm_email_code(user): code = EmailConfirmation.create(user=user, email_confirm=True) return code diff --git a/endpoints/api.py b/endpoints/api.py index a1a769744..383f85ad5 100644 --- a/endpoints/api.py +++ b/endpoints/api.py @@ -151,6 +151,14 @@ def user_view(user): organizations = model.get_user_organizations(user.username) + def login_view(login): + return { + 'service': login.service.name, + 'service_identifier': login.service_ident, + } + + logins = model.list_federated_logins(user) + return { 'verified': user.verified, 'anonymous': False, @@ -159,6 +167,7 @@ def user_view(user): 'gravatar': compute_hash(user.email), 'askForPassword': user.password_hash is None, 'organizations': [org_view(o) for o in organizations], + 'logins': [login_view(login) for login in logins], 'can_create_repo': True, 'invoice_email': user.invoice_email } diff --git a/endpoints/web.py b/endpoints/web.py index baca58a93..dcfd81d5a 100644 --- a/endpoints/web.py +++ b/endpoints/web.py @@ -4,7 +4,7 @@ import stripe from flask import (abort, redirect, request, url_for, render_template, make_response, Response) -from flask.ext.login import current_user +from flask.ext.login import login_required, current_user from urlparse import urlparse from data import model @@ -155,8 +155,7 @@ def receipt(): abort(404) -@app.route('/oauth2/github/callback', methods=['GET']) -def github_oauth_callback(): +def exchange_github_code_for_token(code): code = request.args.get('code') payload = { 'client_id': app.config['GITHUB_CLIENT_ID'], @@ -171,13 +170,23 @@ def github_oauth_callback(): params=payload, headers=headers) token = get_access_token.json()['access_token'] + return token + +def get_github_user(token): token_param = { 'access_token': token, } get_user = requests.get(app.config['GITHUB_USER_URL'], params=token_param) - user_data = get_user.json() + return get_user.json() + + +@app.route('/oauth2/github/callback', methods=['GET']) +def github_oauth_callback(): + token = exchange_github_code_for_token(request.args.get('code')) + user_data = get_github_user(token) + username = user_data['login'] github_id = user_data['id'] @@ -218,6 +227,16 @@ def github_oauth_callback(): return render_page_template('githuberror.html') +@app.route('/oauth2/github/callback/attach', methods=['GET']) +@login_required +def github_oauth_attach(): + token = exchange_github_code_for_token(request.args.get('code')) + user_data = get_github_user(token) + github_id = user_data['id'] + user_obj = current_user.db_user() + model.attach_federated_login(user_obj, 'github', github_id) + + @app.route('/confirm', methods=['GET']) def confirm_email(): code = request.values['code'] diff --git a/static/css/quay.css b/static/css/quay.css index f9d233e57..b226e6593 100644 --- a/static/css/quay.css +++ b/static/css/quay.css @@ -1879,6 +1879,10 @@ p.editable:hover i { margin-top: 10px; } +.user-admin .check-green { + color: #46ac39; +} + #image-history-container { overflow: hidden; min-height: 400px; diff --git a/static/js/app.js b/static/js/app.js index 0b881200b..c85d5d304 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -265,7 +265,8 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest username: null, email: null, askForPassword: false, - organizations: [] + organizations: [], + logins: [] } var userService = {} @@ -358,9 +359,11 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest if ($location.host() === 'quay.io') { keyService['stripePublishableKey'] = 'pk_live_P5wLU0vGdHnZGyKnXlFG4oiu'; keyService['githubClientId'] = '5a8c08b06c48d89d4d1e'; + keyService['githubRedirectUri'] = 'https://quay.io/oauth2/github/callback'; } else { keyService['stripePublishableKey'] = 'pk_test_uEDHANKm9CHCvVa2DLcipGRh'; keyService['githubClientId'] = 'cfbc4aca88e5c1b40679'; + keyService['githubRedirectUri'] = 'http://localhost:5000/oauth2/github/callback'; } return keyService; diff --git a/static/js/controllers.js b/static/js/controllers.js index 900a12cb8..8768e7734 100644 --- a/static/js/controllers.js +++ b/static/js/controllers.js @@ -868,7 +868,7 @@ function RepoAdminCtrl($scope, Restangular, ApiService, $routeParams, $rootScope fetchRepository(); } -function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, UserService, KeyService, $routeParams) { +function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, UserService, KeyService, $routeParams, $http) { if ($routeParams['migrate']) { $('#migrateTab').tab('show') } @@ -876,6 +876,15 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use UserService.updateUserIn($scope, function(user) { $scope.askForPassword = user.askForPassword; $scope.cuser = jQuery.extend({}, user); + + for (var i = 0; i < $scope.cuser.logins.length; i++) { + if ($scope.cuser.logins[i].service == 'github') { + var githubId = $scope.cuser.logins[i].service_identifier; + $http.get('https://api.github.com/user/' + githubId).success(function(resp) { + $scope.githubLogin = resp.login; + }); + } + } }); $scope.readyForPlan = function() { diff --git a/static/partials/user-admin.html b/static/partials/user-admin.html index 1e5f0ab82..7080e3723 100644 --- a/static/partials/user-admin.html +++ b/static/partials/user-admin.html @@ -31,6 +31,7 @@