155 lines
5.5 KiB
Python
155 lines
5.5 KiB
Python
# Copyright (c) 2013-2014 Rackspace, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
# implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""
|
|
Barbican defined mime-types
|
|
"""
|
|
|
|
from barbican.common import utils
|
|
|
|
|
|
# Supported content types
|
|
# Note: These types may be provided by clients.
|
|
PLAIN_TEXT = ['text/plain',
|
|
'text/plain;charset=utf-8',
|
|
'text/plain; charset=utf-8']
|
|
PLAIN_TEXT_CHARSETS = ['utf-8']
|
|
BINARY = ['application/octet-stream',
|
|
'application/pkcs8']
|
|
SUPPORTED = PLAIN_TEXT + BINARY
|
|
|
|
# Normalizes client types to internal types.
|
|
INTERNAL_CTYPES = {'text/plain': 'text/plain',
|
|
'text/plain;charset=utf-8': 'text/plain',
|
|
'text/plain; charset=utf-8': 'text/plain',
|
|
'application/octet-stream': 'application/octet-stream',
|
|
'application/pkcs8': 'application/pkcs8',
|
|
'application/aes': 'application/aes'}
|
|
|
|
# Maps mime-types used to specify secret data formats to the types that can
|
|
# be requested for secrets via GET calls.
|
|
# Note: Raw client types are converted into the 'INTERNAL_CTYPES' types
|
|
# which are then used as the keys to the 'CTYPES_MAPPINGS' below.
|
|
CTYPES_PLAIN = {'default': 'text/plain'}
|
|
CTYPES_BINARY = {'default': 'application/octet-stream'}
|
|
CTYPES_PKCS8 = {'default': 'application/pkcs8'}
|
|
CTYPES_AES = {'default': 'application/aes'}
|
|
CTYPES_MAPPINGS = {'text/plain': CTYPES_PLAIN,
|
|
'application/octet-stream': CTYPES_BINARY,
|
|
'application/pkcs8': CTYPES_PKCS8,
|
|
'application/aes': CTYPES_AES}
|
|
|
|
# Supported encodings
|
|
ENCODINGS = ['base64']
|
|
|
|
# Maps normalized content-types to supported encoding(s)
|
|
CTYPES_TO_ENCODINGS = {'text/plain': None,
|
|
'application/octet-stream': ['base64', 'binary'],
|
|
'application/pkcs8': ['base64', 'binary'],
|
|
'application/aes': None}
|
|
|
|
|
|
def normalize_content_type(mime_type):
|
|
"""Normalize the supplied content-type to an internal form."""
|
|
stripped = list(map(lambda x: x.strip(), mime_type.split(';')))
|
|
mime = stripped[0].lower()
|
|
if len(stripped) > 1:
|
|
# mime type includes charset
|
|
charset_type = stripped[1].lower()
|
|
if '=' not in charset_type:
|
|
# charset is malformed
|
|
return mime_type
|
|
else:
|
|
charset = list(map(lambda x: x.strip(),
|
|
charset_type.split('=')))[1]
|
|
if charset not in PLAIN_TEXT_CHARSETS:
|
|
# unsupported charset
|
|
return mime_type
|
|
return INTERNAL_CTYPES.get(mime, mime_type)
|
|
|
|
|
|
def is_supported(mime_type):
|
|
normalized_type = normalize_content_type(mime_type)
|
|
return normalized_type in SUPPORTED
|
|
|
|
|
|
def is_base64_encoding_supported(mime_type):
|
|
if is_supported(mime_type):
|
|
encodings = CTYPES_TO_ENCODINGS[INTERNAL_CTYPES[mime_type]]
|
|
return encodings and ('base64' in encodings)
|
|
return False
|
|
|
|
|
|
def is_content_type_with_encoding_supported(content_type, content_encoding):
|
|
if not is_supported(content_type):
|
|
return False
|
|
normalized_type = normalize_content_type(content_type)
|
|
encodings = CTYPES_TO_ENCODINGS[INTERNAL_CTYPES[normalized_type]]
|
|
if encodings:
|
|
return content_encoding in encodings
|
|
else:
|
|
return content_encoding is None
|
|
|
|
|
|
def get_supported_encodings(content_type):
|
|
normalized_type = normalize_content_type(content_type)
|
|
return CTYPES_TO_ENCODINGS[INTERNAL_CTYPES[normalized_type]]
|
|
|
|
|
|
def is_base64_processing_needed(content_type, content_encoding):
|
|
content_encodings = utils.get_accepted_encodings_direct(content_encoding)
|
|
if content_encodings:
|
|
if 'base64' not in content_encodings:
|
|
return False
|
|
if is_supported(content_type):
|
|
encodings = CTYPES_TO_ENCODINGS[INTERNAL_CTYPES[content_type]]
|
|
return encodings and 'base64' in encodings
|
|
return False
|
|
|
|
|
|
def use_binary_content_as_is(content_type, content_encoding):
|
|
"""Checks if headers are valid to allow binary content as-is."""
|
|
content_encodings = utils.get_accepted_encodings_direct(content_encoding)
|
|
if content_encodings:
|
|
if 'binary' not in content_encodings:
|
|
return False
|
|
if is_supported(content_type):
|
|
encodings = CTYPES_TO_ENCODINGS[INTERNAL_CTYPES.get(content_type)]
|
|
return encodings and 'binary' in encodings
|
|
return INTERNAL_CTYPES.get(content_type) in BINARY
|
|
|
|
|
|
def augment_fields_with_content_types(secret):
|
|
"""Add content-types and encodings information to a Secret's fields.
|
|
|
|
Generate a dict of content types based on the data associated
|
|
with the specified secret.
|
|
|
|
:param secret: The models.Secret instance to add 'content_types' to.
|
|
"""
|
|
|
|
fields = secret.to_dict_fields()
|
|
|
|
if not secret.secret_store_metadata:
|
|
return fields
|
|
|
|
content_type = secret.secret_store_metadata.get('content_type')
|
|
if content_type and content_type.value in CTYPES_MAPPINGS:
|
|
fields.update(
|
|
{'content_types': CTYPES_MAPPINGS[content_type.value]}
|
|
)
|
|
|
|
return fields
|