mirror of
https://github.com/ZwareBear/awx.git
synced 2026-03-30 20:53:41 -05:00
* python-social-auth has SOCIAL_AUTH_SAML_SECURITY_CONFIG, which is forwarded to python-saml settings configuration. This commit exposes SOCIAL_AUTH_SAML_SECURITY_CONFIG to configure tower in tower to allow users to set requestedAuthnContext, which will disable the requesting of password type auth from the idp. Thus, it's up to the idp to choose which auth to use (i.e. 2-factor).
139 lines
5.0 KiB
Python
139 lines
5.0 KiB
Python
# Python
|
|
import logging
|
|
import urlparse
|
|
|
|
# Django
|
|
from django.core.validators import URLValidator
|
|
from django.utils.translation import ugettext_lazy as _
|
|
|
|
# Django REST Framework
|
|
from rest_framework.fields import * # noqa
|
|
|
|
import six
|
|
|
|
logger = logging.getLogger('awx.conf.fields')
|
|
|
|
# Use DRF fields to convert/validate settings:
|
|
# - to_representation(obj) should convert a native Python object to a primitive
|
|
# serializable type. This primitive type will be what is presented in the API
|
|
# and stored in the JSON field in the datbase.
|
|
# - to_internal_value(data) should convert the primitive type back into the
|
|
# appropriate Python type to be used in settings.
|
|
|
|
|
|
class CharField(CharField):
|
|
|
|
def to_representation(self, value):
|
|
# django_rest_frameworks' default CharField implementation casts `None`
|
|
# to a string `"None"`:
|
|
#
|
|
# https://github.com/tomchristie/django-rest-framework/blob/cbad236f6d817d992873cd4df6527d46ab243ed1/rest_framework/fields.py#L761
|
|
if value is None:
|
|
return None
|
|
return super(CharField, self).to_representation(value)
|
|
|
|
|
|
class IntegerField(IntegerField):
|
|
|
|
def get_value(self, dictionary):
|
|
ret = super(IntegerField, self).get_value(dictionary)
|
|
# Handle UI corner case
|
|
if ret == '' and self.allow_null and not getattr(self, 'allow_blank', False):
|
|
return None
|
|
return ret
|
|
|
|
|
|
class StringListField(ListField):
|
|
|
|
child = CharField()
|
|
|
|
def to_representation(self, value):
|
|
if value is None and self.allow_null:
|
|
return None
|
|
return super(StringListField, self).to_representation(value)
|
|
|
|
|
|
class StringListBooleanField(ListField):
|
|
|
|
default_error_messages = {
|
|
'type_error': _('Expected None, True, False, a string or list of strings but got {input_type} instead.'),
|
|
}
|
|
child = CharField()
|
|
|
|
def to_representation(self, value):
|
|
if isinstance(value, (list, tuple)):
|
|
return super(StringListBooleanField, self).to_representation(value)
|
|
elif value in fields.NullBooleanField.TRUE_VALUES:
|
|
return True
|
|
elif value in fields.NullBooleanField.FALSE_VALUES:
|
|
return False
|
|
elif value in fields.NullBooleanField.NULL_VALUES:
|
|
return None
|
|
elif isinstance(value, basestring):
|
|
return self.child.to_representation(value)
|
|
else:
|
|
self.fail('type_error', input_type=type(value))
|
|
|
|
def to_internal_value(self, data):
|
|
if isinstance(data, (list, tuple)):
|
|
return super(StringListBooleanField, self).to_internal_value(data)
|
|
elif data in fields.NullBooleanField.TRUE_VALUES:
|
|
return True
|
|
elif data in fields.NullBooleanField.FALSE_VALUES:
|
|
return False
|
|
elif data in fields.NullBooleanField.NULL_VALUES:
|
|
return None
|
|
elif isinstance(data, basestring):
|
|
return self.child.run_validation(data)
|
|
else:
|
|
self.fail('type_error', input_type=type(data))
|
|
|
|
|
|
class URLField(CharField):
|
|
|
|
def __init__(self, **kwargs):
|
|
schemes = kwargs.pop('schemes', None)
|
|
self.allow_plain_hostname = kwargs.pop('allow_plain_hostname', False)
|
|
super(URLField, self).__init__(**kwargs)
|
|
validator_kwargs = dict(message=_('Enter a valid URL'))
|
|
if schemes is not None:
|
|
validator_kwargs['schemes'] = schemes
|
|
self.validators.append(URLValidator(**validator_kwargs))
|
|
|
|
def to_representation(self, value):
|
|
if value is None:
|
|
return ''
|
|
return super(URLField, self).to_representation(value)
|
|
|
|
def run_validators(self, value):
|
|
if self.allow_plain_hostname:
|
|
try:
|
|
url_parts = urlparse.urlsplit(value)
|
|
if url_parts.hostname and '.' not in url_parts.hostname:
|
|
netloc = '{}.local'.format(url_parts.hostname)
|
|
if url_parts.port:
|
|
netloc = '{}:{}'.format(netloc, url_parts.port)
|
|
if url_parts.username:
|
|
if url_parts.password:
|
|
netloc = '{}:{}@{}' % (url_parts.username, url_parts.password, netloc)
|
|
else:
|
|
netloc = '{}@{}' % (url_parts.username, netloc)
|
|
value = urlparse.urlunsplit([url_parts.scheme, netloc, url_parts.path, url_parts.query, url_parts.fragment])
|
|
except Exception:
|
|
raise # If something fails here, just fall through and let the validators check it.
|
|
super(URLField, self).run_validators(value)
|
|
|
|
|
|
class KeyValueField(DictField):
|
|
child = CharField()
|
|
default_error_messages = {
|
|
'invalid_child': _('"{input}" is not a valid string.')
|
|
}
|
|
|
|
def to_internal_value(self, data):
|
|
ret = super(KeyValueField, self).to_internal_value(data)
|
|
for value in data.values():
|
|
if not isinstance(value, six.string_types + six.integer_types + (float,)):
|
|
self.fail('invalid_child', input=value)
|
|
return ret
|