diff --git a/awx/conf/fields.py b/awx/conf/fields.py index 9a748593c7..8e93ad7ad3 100644 --- a/awx/conf/fields.py +++ b/awx/conf/fields.py @@ -53,6 +53,42 @@ class StringListField(ListField): 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): diff --git a/awx/sso/conf.py b/awx/sso/conf.py index c75ec4e250..001c527f45 100644 --- a/awx/sso/conf.py +++ b/awx/sso/conf.py @@ -70,6 +70,11 @@ SOCIAL_AUTH_TEAM_MAP_PLACEHOLDER = collections.OrderedDict([ ])), ]) +SOCIAL_AUTH_SAML_SECURITY_CONFIG_HELP_TEXT = _('''\ +Extra https://github.com/onelogin/python-saml#settings\ +''') + + ############################################################################### # AUTHENTICATION BACKENDS DYNAMIC SETTING ############################################################################### @@ -1061,6 +1066,20 @@ register( feature_required='enterprise_auth', ) +register( + 'SOCIAL_AUTH_SAML_SECURITY_CONFIG', + field_class=fields.SAMLSecurityField, + allow_null=True, + default=None, + label=_('SAML Security Config'), + help_text=SOCIAL_AUTH_SAML_SECURITY_CONFIG_HELP_TEXT, + category=_('SAML'), + category_slug='saml', + #placeholder=SOCIAL_AUTH_TEAM_MAP_PLACEHOLDER, + placeholder=collections.OrderedDict(), + feature_required='enterprise_auth', +) + register( 'SOCIAL_AUTH_SAML_ORGANIZATION_MAP', field_class=fields.SocialOrganizationMapField, diff --git a/awx/sso/fields.py b/awx/sso/fields.py index c2400bae31..a483044464 100644 --- a/awx/sso/fields.py +++ b/awx/sso/fields.py @@ -345,41 +345,10 @@ class LDAPUserFlagsField(fields.DictField): return data -class LDAPDNMapField(fields.ListField): +class LDAPDNMapField(fields.StringListBooleanField): - default_error_messages = { - 'type_error': _('Expected None, True, False, a string or list of strings but got {input_type} instead.'), - } child = LDAPDNField() - def to_representation(self, value): - if isinstance(value, (list, tuple)): - return super(LDAPDNMapField, 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(LDAPDNMapField, 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 BaseDictWithChildField(fields.DictField): @@ -649,3 +618,28 @@ class SAMLIdPField(BaseDictWithChildField): class SAMLEnabledIdPsField(fields.DictField): child = SAMLIdPField() + + +class SAMLSecurityField(fields.DictField): + + child_fields = { + 'nameIdEncrypted': fields.BooleanField(required=False), + 'authnRequestsSigned': fields.BooleanField(required=False), + 'logoutRequestSigned': fields.BooleanField(required=False), + 'logoutResponseSigned': fields.BooleanField(required=False), + 'signMetadata': fields.BooleanField(required=False), + 'wantMessagesSigned': fields.BooleanField(required=False), + 'wantAssertionsSigned': fields.BooleanField(required=False), + 'wantAssertionsEncrypted': fields.BooleanField(required=False), + 'wantNameId': fields.BooleanField(required=False), + 'wantNameIdEncrypted': fields.BooleanField(required=False), + 'wantAttributeStatement': fields.BooleanField(required=False), + 'requestedAuthnContext': fields.StringListBooleanField(required=False), + 'requestedAuthnContextComparison': fields.CharField(required=False), + 'metadataValidUntil': fields.CharField(allow_null=True, required=False), + 'metadataCacheDuration': fields.CharField(allow_null=True, required=False), + 'signatureAlgorithm': fields.CharField(allow_null=True, required=False), + 'digestAlgorithm': fields.CharField(allow_null=True, required=False), + } + allow_unknown_keys = True +