Make sure to verify service names on key creation
This commit is contained in:
parent
dc9bcec9ce
commit
28a80ef6a9
3 changed files with 24 additions and 1 deletions
|
@ -84,6 +84,10 @@ class ServiceKeyAlreadyApproved(DataModelException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceNameInvalid(DataModelException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TooManyLoginAttemptsException(Exception):
|
class TooManyLoginAttemptsException(Exception):
|
||||||
def __init__(self, message, retry_after):
|
def __init__(self, message, retry_after):
|
||||||
super(TooManyLoginAttemptsException, self).__init__(message)
|
super(TooManyLoginAttemptsException, self).__init__(message)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import re
|
||||||
|
|
||||||
from calendar import timegm
|
from calendar import timegm
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from peewee import JOIN_LEFT_OUTER
|
from peewee import JOIN_LEFT_OUTER
|
||||||
|
@ -6,11 +8,14 @@ from Crypto.PublicKey import RSA
|
||||||
from jwkest.jwk import RSAKey
|
from jwkest.jwk import RSAKey
|
||||||
|
|
||||||
from data.database import db_for_update, User, ServiceKey, ServiceKeyApproval
|
from data.database import db_for_update, User, ServiceKey, ServiceKeyApproval
|
||||||
from data.model import ServiceKeyDoesNotExist, ServiceKeyAlreadyApproved, db_transaction, config
|
from data.model import (ServiceKeyDoesNotExist, ServiceKeyAlreadyApproved, ServiceNameInvalid,
|
||||||
|
db_transaction, config)
|
||||||
from data.model.notification import create_notification, delete_all_notifications_by_path_prefix
|
from data.model.notification import create_notification, delete_all_notifications_by_path_prefix
|
||||||
from util.security.fingerprint import canonical_kid
|
from util.security.fingerprint import canonical_kid
|
||||||
|
|
||||||
|
|
||||||
|
_SERVICE_NAME_REGEX = re.compile(r'^[a-z0-9_]+$')
|
||||||
|
|
||||||
def _expired_keys_clause(service):
|
def _expired_keys_clause(service):
|
||||||
return ((ServiceKey.service == service) &
|
return ((ServiceKey.service == service) &
|
||||||
(ServiceKey.expiration_date <= datetime.utcnow()))
|
(ServiceKey.expiration_date <= datetime.utcnow()))
|
||||||
|
@ -33,6 +38,11 @@ def _gc_expired(service):
|
||||||
_stale_unapproved_keys_clause(service)).execute()
|
_stale_unapproved_keys_clause(service)).execute()
|
||||||
|
|
||||||
|
|
||||||
|
def _verify_service_name(service_name):
|
||||||
|
if not _SERVICE_NAME_REGEX.match(service_name):
|
||||||
|
raise ServiceNameInvalid
|
||||||
|
|
||||||
|
|
||||||
def _notify_superusers(key):
|
def _notify_superusers(key):
|
||||||
notification_metadata = {
|
notification_metadata = {
|
||||||
'name': key.name,
|
'name': key.name,
|
||||||
|
@ -53,6 +63,8 @@ def _notify_superusers(key):
|
||||||
|
|
||||||
|
|
||||||
def create_service_key(name, kid, service, jwk, metadata, expiration_date, rotation_duration=None):
|
def create_service_key(name, kid, service, jwk, metadata, expiration_date, rotation_duration=None):
|
||||||
|
_verify_service_name(service)
|
||||||
|
|
||||||
key = ServiceKey.create(name=name, kid=kid, service=service, jwk=jwk, metadata=metadata,
|
key = ServiceKey.create(name=name, kid=kid, service=service, jwk=jwk, metadata=metadata,
|
||||||
expiration_date=expiration_date, rotation_duration=rotation_duration)
|
expiration_date=expiration_date, rotation_duration=rotation_duration)
|
||||||
|
|
||||||
|
|
|
@ -233,6 +233,13 @@ class KeyServerTestCase(EndpointTestCase):
|
||||||
payload = self._get_test_jwt_payload()
|
payload = self._get_test_jwt_payload()
|
||||||
token = jwt.encode(payload, private_key.exportKey('PEM'), 'RS256')
|
token = jwt.encode(payload, private_key.exportKey('PEM'), 'RS256')
|
||||||
|
|
||||||
|
# Invalid service name should yield a 400.
|
||||||
|
self.putResponse('key_server.put_service_key', service='sample service', kid='kid420',
|
||||||
|
headers={
|
||||||
|
'Authorization': 'Bearer %s' % token,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}, data=jwk, expected_code=400)
|
||||||
|
|
||||||
# Publish a new key
|
# Publish a new key
|
||||||
with assert_action_logged('service_key_create'):
|
with assert_action_logged('service_key_create'):
|
||||||
self.putResponse('key_server.put_service_key', service='sample_service', kid='kid420',
|
self.putResponse('key_server.put_service_key', service='sample_service', kid='kid420',
|
||||||
|
|
Reference in a new issue