Merge branch 'master' of bitbucket.org:yackob03/quay

This commit is contained in:
Jake Moshenko 2014-09-15 15:59:18 -04:00
commit 2b59a0cbe1
11 changed files with 89 additions and 5 deletions

View file

@ -135,8 +135,15 @@ def process_token(auth):
logger.warning('Invalid token format: %s' % auth)
abort(401, message='Invalid token format: %(auth)s', issue='invalid-auth-token', auth=auth)
token_vals = {val[0]: val[1] for val in
def safe_get(lst, index, default_value):
try:
return lst[index]
except IndexError:
return default_value
token_vals = {val[0]: safe_get(val, 1, '') for val in
(detail.split('=') for detail in token_details)}
if 'signature' not in token_vals:
logger.warning('Token does not contain signature: %s' % auth)
abort(401, message='Token does not contain a valid signature: %(auth)s',

View file

@ -1830,6 +1830,16 @@ def get_active_users():
def get_active_user_count():
return get_active_users().count()
def detach_external_login(user, service_name):
try:
service = LoginService.get(name = service_name)
except LoginService.DoesNotExist:
return
FederatedLogin.delete().where(FederatedLogin.user == user,
FederatedLogin.service == service).execute()
def delete_user(user):
user.delete_instance(recursive=True, delete_nullable=True)

View file

@ -46,7 +46,7 @@ class DatabaseAuthorizationProvider(AuthorizationProvider):
def validate_redirect_uri(self, client_id, redirect_uri):
try:
app = OAuthApplication.get(client_id=client_id)
if app.redirect_uri and redirect_uri.startswith(app.redirect_uri):
if app.redirect_uri and redirect_uri and redirect_uri.startswith(app.redirect_uri):
return True
return False
except OAuthApplication.DoesNotExist:

View file

@ -408,6 +408,19 @@ class Signout(ApiResource):
return {'success': True}
@resource('/v1/detachexternal/<servicename>')
@internal_only
class DetachExternal(ApiResource):
""" Resource for detaching an external login. """
@require_user_admin
@nickname('detachExternalLogin')
def post(self, servicename):
""" Request that the current user be detached from the external login service. """
model.detach_external_login(get_authenticated_user(), servicename)
return {'success': True}
@resource("/v1/recovery")
@internal_only
class Recovery(ApiResource):

View file

@ -66,6 +66,9 @@ def generate_headers(role='read'):
@index.route('/users/', methods=['POST'])
def create_user():
user_data = request.get_json()
if not 'username' in user_data:
abort(400, 'Missing username')
username = user_data['username']
password = user_data.get('password', '')

View file

@ -556,7 +556,7 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
// If an error occurred, report it and done.
if (ping < 0) {
cached['pings'] = [-1];
invokeCallback($scope, pings, callback);
invokeCallback($scope, [-1], callback);
return;
}
@ -1518,7 +1518,12 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
};
notificationService.getPage = function(notification) {
var page = notificationKinds[notification['kind']]['page'];
var kindInfo = notificationKinds[notification['kind']];
if (!kindInfo) {
return null;
}
var page = kindInfo['page'];
if (typeof page != 'string') {
page = page(notification['metadata']);
}

View file

@ -1781,6 +1781,18 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
UIService.showFormError('#changePasswordForm', result);
});
};
$scope.detachExternalLogin = function(kind) {
var params = {
'servicename': kind
};
ApiService.detachExternalLogin(null, params).then(function() {
$scope.hasGithubLogin = false;
$scope.hasGoogleLogin = false;
UserService.load();
}, ApiService.errorDisplay('Count not detach service'));
};
}
function ImageViewCtrl($scope, $routeParams, $rootScope, $timeout, ApiService, ImageMetadataService) {

View file

@ -177,10 +177,14 @@
<div ng-show="hasGithubLogin && githubLogin" class="lead col-md-8">
<i class="fa fa-github fa-lg" style="margin-right: 6px;" data-title="GitHub" bs-tooltip="tooltip.title"></i>
<b><a href="https://github.com/{{githubLogin}}" target="_blank">{{githubLogin}}</a></b>
<span class="delete-ui" button-title="'Detach'" delete-title="'Detach Account'" style="margin-left: 10px"
perform-delete="detachExternalLogin('github')"></span>
</div>
<div ng-show="hasGithubLogin && !githubLogin" class="lead col-md-8">
<i class="fa fa-github fa-lg" style="margin-right: 6px;" data-title="GitHub" bs-tooltip="tooltip.title"></i>
Account attached to Github Account
<span class="delete-ui" button-title="'Detach'" delete-title="'Detach Account'" style="margin-left: 10px"
perform-delete="detachExternalLogin('github')"></span>
</div>
<div ng-show="!hasGithubLogin" class="col-md-4">
<span class="external-login-button" provider="github" action="attach"></span>
@ -197,10 +201,14 @@
<div ng-show="hasGoogleLogin && googleLogin" class="lead col-md-8">
<i class="fa fa-google fa-lg" style="margin-right: 6px;" data-title="Google" bs-tooltip="tooltip.title"></i>
<b>{{ googleLogin }}</b>
<span class="delete-ui" button-title="'Detach'" delete-title="'Detach Account'" style="margin-left: 10px"
perform-delete="detachExternalLogin('google')"></span>
</div>
<div ng-show="hasGoogleLogin && !googleLogin" class="lead col-md-8">
<i class="fa fa-google fa-lg" style="margin-right: 6px;" data-title="Google" bs-tooltip="tooltip.title"></i>
Account attached to Google Account
<span class="delete-ui" button-title="'Detach'" delete-title="'Detach Account'" style="margin-left: 10px"
perform-delete="detachExternalLogin('google')"></span>
</div>
<div ng-show="!hasGoogleLogin" class="col-md-4">
<span class="external-login-button" provider="google" action="attach"></span>

View file

@ -205,6 +205,9 @@ class _CloudStorage(BaseStorage):
path = self._init_path(path)
key = self._key_class(self._cloud_bucket, path)
k = self._cloud_bucket.lookup(key)
if k is None:
raise IOError('No such key: \'{0}\''.format(path))
return k.etag[1:-1][:7]

View file

@ -24,7 +24,7 @@ from endpoints.api.repoemail import RepositoryAuthorizedEmail
from endpoints.api.repositorynotification import RepositoryNotification, RepositoryNotificationList
from endpoints.api.user import (PrivateRepositories, ConvertToOrganization, Recovery, Signout,
Signin, User, UserAuthorizationList, UserAuthorization, UserNotification,
VerifyUser)
VerifyUser, DetachExternal)
from endpoints.api.repotoken import RepositoryToken, RepositoryTokenList
from endpoints.api.prototype import PermissionPrototype, PermissionPrototypeList
from endpoints.api.logs import UserLogs, OrgLogs, RepositoryLogs
@ -435,6 +435,24 @@ class TestSignin(ApiTestCase):
self._run_test('POST', 403, 'devtable', {u'username': 'E9RY', u'password': 'LQ0N'})
class TestDetachExternal(ApiTestCase):
def setUp(self):
ApiTestCase.setUp(self)
self._set_url(DetachExternal, servicename='someservice')
def test_post_anonymous(self):
self._run_test('POST', 401, None, {})
def test_post_freshuser(self):
self._run_test('POST', 200, 'freshuser', {})
def test_post_reader(self):
self._run_test('POST', 200, 'reader', {})
def test_post_devtable(self):
self._run_test('POST', 200, 'devtable', {})
class TestVerifyUser(ApiTestCase):
def setUp(self):
ApiTestCase.setUp(self)

View file

@ -15,4 +15,9 @@ for index, command in reversed(list(enumerate(parsed_dockerfile.commands))):
parsed_dockerfile.commands.insert(new_command_index, env_command)
break
image_and_tag_tuple = parsed_dockerfile.get_image_and_tag()
print image_and_tag_tuple
if image_and_tag_tuple is None or image_and_tag_tuple[0] is None:
raise Exception('Missing FROM command in Dockerfile')
print serialize_dockerfile(parsed_dockerfile)