allow support for saml + 2-factor

* 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).
This commit is contained in:
Chris Meyers 2017-11-17 09:25:50 -05:00
parent 71127c039d
commit 98f2d936d9
3 changed files with 81 additions and 32 deletions

View File

@ -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):

View File

@ -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,

View File

@ -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