Add API usage tests
This commit is contained in:
parent
11ff3e9b59
commit
fb1dca4e94
4 changed files with 194 additions and 20 deletions
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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, {})
|
||||
|
|
|
@ -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)
|
||||
|
|
Reference in a new issue