Add API usage tests

This commit is contained in:
Joseph Schorr 2016-04-05 15:27:45 -04:00 committed by Jimmy Zelinskie
parent 11ff3e9b59
commit fb1dca4e94
4 changed files with 194 additions and 20 deletions

View file

@ -123,7 +123,7 @@ def approve_service_key(kid, approver, approval_type, notes=''):
delete_all_notifications_by_path_prefix('/service_key_approval/{0}'.format(kid))
_gc_expired(key.service)
return key
def _list_service_keys_query(kid=None, service=None, approved_only=False):
query = ServiceKey.select().join(ServiceKeyApproval, JOIN_LEFT_OUTER)

View file

@ -5,7 +5,6 @@ import logging
import os
import string
from calendar import timegm
from datetime import datetime
from hashlib import sha256
from random import SystemRandom
@ -600,8 +599,8 @@ class SuperUserServiceKeyManagement(ApiResource):
'auto_approved': True,
}
log_action('service_key_create', user.username, key_log_metadata)
log_action('service_key_approve', user.username, key_log_metadata)
log_action('service_key_create', None, key_log_metadata)
log_action('service_key_approve', None, key_log_metadata)
return jsonify({
'kid': kid,
@ -616,7 +615,7 @@ class SuperUserServiceKeyManagement(ApiResource):
@resource('/v1/superuser/keys/<kid>')
@path_param('kid', 'The unique identifier for a service key')
@show_if(features.SUPER_USERS)
class SuperUserServiceKeyUpdater(ApiResource):
class SuperUserServiceKey(ApiResource):
""" Resource for managing service keys. """
schemas = {
'PutServiceKey': {
@ -640,6 +639,19 @@ class SuperUserServiceKeyUpdater(ApiResource):
},
}
@verify_not_prod
@nickname('getServiceKey')
@require_scope(scopes.SUPERUSER)
def get(self, kid):
if SuperUserPermission().can():
try:
key = model.service_keys.get_service_key(kid)
return jsonify(key_view(key))
except model.service_keys.ServiceKeyDoesNotExist:
abort(404)
abort(403)
@require_fresh_login
@verify_not_prod
@nickname('updateServiceKey')
@ -675,13 +687,13 @@ class SuperUserServiceKeyUpdater(ApiResource):
'expiration_date': expiration_date,
})
log_action('service_key_extend', user.username, key_log_metadata)
log_action('service_key_extend', None, key_log_metadata)
model.service_keys.set_key_expiration(kid, expiration_date)
if 'name' in body or 'metadata' in body:
model.service_keys.update_service_key(kid, body.get('name'), body.get('metadata'))
log_action('service_key_modify', user.username, key_log_metadata)
log_action('service_key_modify', None, key_log_metadata)
return jsonify(key_view(model.service_keys.get_service_key(kid)))
@ -693,7 +705,10 @@ class SuperUserServiceKeyUpdater(ApiResource):
@require_scope(scopes.SUPERUSER)
def delete(self, kid):
if SuperUserPermission().can():
key = model.service_keys.delete_service_key(kid)
try:
key = model.service_keys.delete_service_key(kid)
except model.service_keys.ServiceKeyDoesNotExist:
abort(404)
key_log_metadata = {
'kid': kid,
@ -703,9 +718,8 @@ class SuperUserServiceKeyUpdater(ApiResource):
'expiration_date': key.expiration_date,
}
user = get_authenticated_user()
log_action('service_key_delete', user.username, key_log_metadata)
return make_response('', 201)
log_action('service_key_delete', None, key_log_metadata)
return make_response('', 204)
abort(403)
@ -734,13 +748,24 @@ class SuperUserServiceKeyApproval(ApiResource):
@verify_not_prod
@nickname('approveServiceKey')
@require_scope(scopes.SUPERUSER)
def put(self, kid):
@validate_json_request('ApproveServiceKey')
def post(self, kid):
if SuperUserPermission().can():
notes = request.get_json().get('notes', '')
approver = get_authenticated_user()
try:
model.service_keys.approve_service_key(kid, approver, ServiceKeyApprovalType.SUPERUSER,
notes=notes)
key = model.service_keys.approve_service_key(kid, approver, ServiceKeyApprovalType.SUPERUSER,
notes=notes)
# Log the approval of the service key.
key_log_metadata = {
'kid': kid,
'service': key.service,
'name': key.name,
'expiration_date': key.expiration_date,
}
log_action('service_key_approve', None, key_log_metadata)
except model.ServiceKeyDoesNotExist:
abort(404)
except model.ServiceKeyAlreadyApproved:

View file

@ -49,7 +49,7 @@ from endpoints.api.superuser import (SuperUserLogs, SuperUserList, SuperUserMana
SuperUserSendRecoveryEmail, ChangeLog,
SuperUserOrganizationManagement, SuperUserOrganizationList,
SuperUserAggregateLogs, SuperUserServiceKeyManagement,
SuperUserServiceKeyUpdater, SuperUserServiceKeyApproval)
SuperUserServiceKey, SuperUserServiceKeyApproval)
from endpoints.api.secscan import RepositoryImageSecurity
@ -3912,6 +3912,25 @@ class TestSuperUserSendRecoveryEmail(ApiTestCase):
self._run_test('POST', 404, 'devtable', None)
class TestSuperUserServiceKeyApproval(ApiTestCase):
def setUp(self):
ApiTestCase.setUp(self)
self._set_url(SuperUserServiceKeyApproval, kid=1234)
def test_post_anonymous(self):
self._run_test('POST', 401, None, {})
def test_post_freshuser(self):
self._run_test('POST', 403, 'freshuser', {})
def test_post_reader(self):
self._run_test('POST', 403, 'reader', {})
def test_post_devtable(self):
self._run_test('POST', 404, 'devtable', {})
class TestSuperUserServiceKeyManagement(ApiTestCase):
def setUp(self):
ApiTestCase.setUp(self)
@ -3942,10 +3961,22 @@ class TestSuperUserServiceKeyManagement(ApiTestCase):
self._run_test('POST', 200, 'devtable', dict(service='someservice', expiration=None))
class TestSuperUserServiceKeyUpdater(ApiTestCase):
class TestSuperUserServiceKey(ApiTestCase):
def setUp(self):
ApiTestCase.setUp(self)
self._set_url(SuperUserServiceKeyUpdater, kid=1234)
self._set_url(SuperUserServiceKey, kid=1234)
def test_get_anonymous(self):
self._run_test('GET', 403, None, None)
def test_get_freshuser(self):
self._run_test('GET', 403, 'freshuser', None)
def test_get_reader(self):
self._run_test('GET', 403, 'reader', None)
def test_get_devtable(self):
self._run_test('GET', 404, 'devtable', None)
def test_delete_anonymous(self):
self._run_test('DELETE', 401, None, None)
@ -3957,7 +3988,7 @@ class TestSuperUserServiceKeyUpdater(ApiTestCase):
self._run_test('DELETE', 403, 'reader', None)
def test_delete_devtable(self):
self._run_test('DELETE', 400, 'devtable', None)
self._run_test('DELETE', 404, 'devtable', None)
def test_put_anonymous(self):
self._run_test('PUT', 401, None, {})

View file

@ -6,12 +6,15 @@ import logging
import re
import json as py_json
from calendar import timegm
from StringIO import StringIO
from urllib import urlencode
from urlparse import urlparse, urlunparse, parse_qs
from playhouse.test_utils import assert_query_count, _QueryLogHandler
from httmock import urlmatch, HTTMock
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend
from endpoints.api import api_bp, api
from endpoints.building import PreparedBuild
@ -20,7 +23,7 @@ from app import app, config_provider
from buildtrigger.basehandler import BuildTriggerHandler
from initdb import setup_database_for_testing, finished_database_for_testing
from data import database, model
from data.database import RepositoryActionCount
from data.database import RepositoryActionCount, LogEntry, LogEntryKind
from endpoints.api.team import TeamMember, TeamMemberList, TeamMemberInvite, OrganizationTeam
from endpoints.api.tag import RepositoryTagImages, RepositoryTag, RevertTag, ListRepositoryTags
@ -53,7 +56,9 @@ from endpoints.api.organization import (OrganizationList, OrganizationMember,
from endpoints.api.repository import RepositoryList, RepositoryVisibility, Repository
from endpoints.api.permission import (RepositoryUserPermission, RepositoryTeamPermission,
RepositoryTeamPermissionList, RepositoryUserPermissionList)
from endpoints.api.superuser import SuperUserLogs, SuperUserList, SuperUserManagement
from endpoints.api.superuser import (SuperUserLogs, SuperUserList, SuperUserManagement,
SuperUserServiceKeyManagement, SuperUserServiceKey,
SuperUserServiceKeyApproval)
from endpoints.api.secscan import RepositoryImageSecurity
from endpoints.api.suconfig import (SuperUserRegistryStatus, SuperUserConfig, SuperUserConfigFile,
SuperUserCreateInitialSuperUser)
@ -3554,6 +3559,119 @@ class TestRepositoryImageSecurity(ApiTestCase):
self.assertEquals(1, response['data']['Layer']['IndexedByVersion'])
class TestSuperUserKeyManagement(ApiTestCase):
def test_get_update_keys(self):
self.login(ADMIN_ACCESS_USER)
json = self.getJsonResponse(SuperUserServiceKeyManagement)
self.assertEquals(3, len(json['keys']))
key = json['keys'][0]
self.assertTrue('name' in key)
self.assertTrue('service' in key)
self.assertTrue('kid' in key)
self.assertTrue('created_date' in key)
self.assertTrue('expiration_date' in key)
self.assertTrue('jwk' in key)
self.assertTrue('approval' in key)
self.assertTrue('metadata' in key)
# Update the key's name.
self.putJsonResponse(SuperUserServiceKey, params=dict(kid=key['kid']),
data=dict(name='somenewname'))
# Ensure the key's name has been changed.
json = self.getJsonResponse(SuperUserServiceKey, params=dict(kid=key['kid']))
self.assertEquals('somenewname', json['name'])
# Ensure a log was added for the modification.
kind = LogEntryKind.get(LogEntryKind.name == 'service_key_modify')
self.assertEquals(1, model.log.LogEntry.select().where(LogEntry.kind == kind).count())
# Update the key's metadata.
self.putJsonResponse(SuperUserServiceKey, params=dict(kid=key['kid']),
data=dict(metadata=dict(foo='bar')))
# Ensure the key's metadata has been changed.
json = self.getJsonResponse(SuperUserServiceKey, params=dict(kid=key['kid']))
self.assertEquals('bar', json['metadata']['foo'])
# Ensure a log was added for the modification.
kind = LogEntryKind.get(LogEntryKind.name == 'service_key_modify')
self.assertEquals(2, model.log.LogEntry.select().where(LogEntry.kind == kind).count())
# Change the key's expiration.
self.putJsonResponse(SuperUserServiceKey, params=dict(kid=key['kid']),
data=dict(expiration=None))
# Ensure the key's expiration has been changed.
json = self.getJsonResponse(SuperUserServiceKey, params=dict(kid=key['kid']))
self.assertIsNone(json['expiration_date'])
# Ensure a log was added for the modification.
kind = LogEntryKind.get(LogEntryKind.name == 'service_key_extend')
self.assertEquals(1, model.log.LogEntry.select().where(LogEntry.kind == kind).count())
# Delete the key.
self.deleteResponse(SuperUserServiceKey, params=dict(kid=key['kid']))
# Ensure the key no longer exists.
self.getResponse(SuperUserServiceKey, params=dict(kid=key['kid']), expected_code=404)
json = self.getJsonResponse(SuperUserServiceKeyManagement)
self.assertEquals(2, len(json['keys']))
# Ensure a log was added for the deletion.
kind = LogEntryKind.get(LogEntryKind.name == 'service_key_delete')
self.assertEquals(1, model.log.LogEntry.select().where(LogEntry.kind == kind).count())
def test_create_key(self):
self.login(ADMIN_ACCESS_USER)
kind = LogEntryKind.get(LogEntryKind.name == 'service_key_create')
existing_log_count = model.log.LogEntry.select().where(LogEntry.kind == kind).count()
new_key = {
'service': 'coolservice',
'name': 'mynewkey',
'metadata': dict(foo='baz'),
'notes': 'whazzup!?',
'expiration': timegm((datetime.datetime.now() + datetime.timedelta(days=1)).utctimetuple()),
}
# Create the key.
json = self.postJsonResponse(SuperUserServiceKeyManagement, data=new_key)
self.assertEquals('mynewkey', json['name'])
self.assertTrue('kid' in json)
self.assertTrue('public_key' in json)
self.assertTrue('private_key' in json)
# Verify the private key is a valid PEM.
serialization.load_pem_private_key(json['private_key'].encode('utf-8'), None, default_backend())
# Verify the key.
kid = json['kid']
json = self.getJsonResponse(SuperUserServiceKey, params=dict(kid=kid))
self.assertEquals('mynewkey', json['name'])
self.assertEquals('coolservice', json['service'])
self.assertEquals('baz', json['metadata']['foo'])
self.assertEquals(kid, json['kid'])
self.assertIsNotNone(json['approval'])
self.assertEquals('ServiceKeyApprovalType.SUPERUSER', json['approval']['approval_type'])
self.assertEquals(ADMIN_ACCESS_USER, json['approval']['approver']['username'])
self.assertEquals('whazzup!?', json['approval']['notes'])
# Ensure that there are logs for the creation and auto-approval.
kind = LogEntryKind.get(LogEntryKind.name == 'service_key_create')
self.assertEquals(existing_log_count + 1, model.log.LogEntry.select().where(LogEntry.kind == kind).count())
kind = LogEntryKind.get(LogEntryKind.name == 'service_key_approve')
self.assertEquals(existing_log_count + 1, model.log.LogEntry.select().where(LogEntry.kind == kind).count())
class TestSuperUserManagement(ApiTestCase):
def test_get_user(self):
self.login(ADMIN_ACCESS_USER)