misc: concatenate strings when possible (#56007)

This commit is contained in:
Valentin Deniaud 2021-08-10 10:47:28 +02:00
parent 208156b2c8
commit f24096f8b8
68 changed files with 424 additions and 365 deletions

View File

@ -136,9 +136,8 @@ class OrganizationalUnit(OrganizationalUnitAbstractBase):
if self.pk and not self.default and self.__class__.objects.get(pk=self.pk).default:
raise ValidationError(
_(
'You cannot unset this organizational '
'unit as the default, but you can set '
'another one as the default.'
'You cannot unset this organizational unit as the default, but you can set another one as'
' the default.'
)
)
if bool(self.clean_unused_accounts_alert) ^ bool(self.clean_unused_accounts_deletion):

View File

@ -205,9 +205,8 @@ class UserChangeForm(BaseUserForm):
password = ReadOnlyPasswordHashField(
label=_("Password"),
help_text=_(
"Raw passwords are not stored, so there is no way to see "
"this user's password, but you can change the password "
"using <a href=\"password/\">this form</a>."
"Raw passwords are not stored, so there is no way to see this user's password, but you can change"
" the password using <a href=\"password/\">this form</a>."
),
)

View File

@ -152,9 +152,7 @@ class RegistrationSerializer(serializers.Serializer):
else:
authorized = request.user.has_perm(perm)
if not authorized:
raise serializers.ValidationError(
_('you are not authorized ' 'to create users in ' 'this ou')
)
raise serializers.ValidationError(_('you are not authorized to create users in this ou'))
User = get_user_model()
if ou:
if app_settings.A2_EMAIL_IS_UNIQUE or app_settings.A2_REGISTRATION_EMAIL_IS_UNIQUE:
@ -280,7 +278,7 @@ class Register(BaseRpcView):
'result': 0,
'errors': {
'__all__': [
'You must set at least a username, an email or ' 'a first name and a last name'
'You must set at least a username, an email or a first name and a last name'
]
},
}
@ -448,7 +446,7 @@ class BaseUserSerializer(serializers.ModelSerializer):
)
except smtplib.SMTPException as e:
logging.getLogger(__name__).error(
'registration mail could not be sent to user %s ' 'created through API: %s', instance, e
'registration mail could not be sent to user %s created through API: %s', instance, e
)
return instance
@ -997,11 +995,9 @@ class RoleMembershipsAPI(ExceptionHandlerMixin, APIView):
try:
uuid = entry['uuid']
except TypeError:
raise ValidationError(_("List elements of the 'data' dict " "entry must be dictionaries"))
raise ValidationError(_("List elements of the 'data' dict entry must be dictionaries"))
except KeyError:
raise ValidationError(
_("Missing 'uuid' key for dict entry %s " "of the 'data' payload") % entry
)
raise ValidationError(_("Missing 'uuid' key for dict entry %s of the 'data' payload") % entry)
try:
self.members.add(User.objects.get(uuid=uuid))
except User.DoesNotExist:

View File

@ -121,8 +121,10 @@ default_settings = dict(
),
A2_REGISTRATION_REDIRECT=Setting(
default=None,
definition='Forced redirection after each redirect, NEXT_URL substring is replaced'
' by the original next_url passed to /accounts/register/',
definition=(
'Forced redirection after each redirect, NEXT_URL substring is replaced by the original next_url'
' passed to /accounts/register/'
),
),
A2_PROFILE_CAN_CHANGE_EMAIL=Setting(default=True, definition='Can user self change their email'),
A2_PROFILE_CAN_EDIT_PROFILE=Setting(default=True, definition='Can user self edit their profile'),
@ -226,30 +228,32 @@ default_settings = dict(
),
A2_LOGIN_FAILURE_COUNT_BEFORE_WARNING=Setting(
default=0,
definition='Failure count before logging a warning to '
'authentic2.user_login_failure. No warning will be send if value is '
'0.',
definition=(
'Failure count before logging a warning to authentic2.user_login_failure. No warning will be send'
' if value is 0.'
),
),
PUSH_PROFILE_UPDATES=Setting(default=False, definition='Push profile update to linked services'),
TEMPLATE_VARS=Setting(default={}, definition='Variable to pass to templates'),
A2_LOGIN_EXPONENTIAL_RETRY_TIMEOUT_FACTOR=Setting(
default=1.8,
definition='exponential backoff factor duration as seconds until ' 'next try after a login failure',
definition='exponential backoff factor duration as seconds until next try after a login failure',
),
A2_LOGIN_EXPONENTIAL_RETRY_TIMEOUT_DURATION=Setting(
default=1,
definition='exponential backoff base factor duration as seconds '
'until next try after a login failure',
definition='exponential backoff base factor duration as seconds until next try after a login failure',
),
A2_LOGIN_EXPONENTIAL_RETRY_TIMEOUT_MAX_DURATION=Setting(
default=3600,
definition='maximum exponential backoff maximum duration as seconds until '
'next try after a login failure',
definition=(
'maximum exponential backoff maximum duration as seconds until next try after a login failure'
),
),
A2_LOGIN_EXPONENTIAL_RETRY_TIMEOUT_MIN_DURATION=Setting(
default=10,
definition='minimum exponential backoff maximum duration as seconds until '
'next try after a login failure',
definition=(
'minimum exponential backoff maximum duration as seconds until next try after a login failure'
),
),
A2_VERIFY_SSL=Setting(default=True, definition='Verify SSL certificate in HTTP requests'),
A2_ATTRIBUTE_KIND_TITLE_CHOICES=Setting(default=(), definition='Choices for the title attribute kind'),
@ -270,24 +274,27 @@ default_settings = dict(
),
A2_USER_FILTER=Setting(
default={},
definition='Filters (as in QuerySet.filter() to apply to User queryset before ' 'authentication',
definition='Filters (as in QuerySet.filter() to apply to User queryset before authentication',
),
A2_USER_EXCLUDE=Setting(
default={},
definition='Exclusion filter (as in QuerySet.exclude() to apply to User queryset before '
'authentication',
definition=(
'Exclusion filter (as in QuerySet.exclude() to apply to User queryset before authentication'
),
),
A2_USER_REMEMBER_ME=Setting(
default=None,
definition='Session duration as seconds when using the remember me '
'checkbox. Truthiness activates the checkbox.',
definition=(
'Session duration as seconds when using the remember me checkbox. Truthiness activates the'
' checkbox.'
),
),
A2_LOGIN_REDIRECT_AUTHENTICATED_USERS_TO_HOMEPAGE=Setting(
default=False, definition='Redirect authenticated users to homepage'
),
A2_LOGIN_DISPLAY_A_CANCEL_BUTTON=Setting(
default=False,
definition='Display a cancel button.' 'This is only applicable for Liberty single sign on requests',
definition='Display a cancel button.This is only applicable for Liberty single sign on requests',
),
A2_SET_RANDOM_PASSWORD_ON_RESET=Setting(
default=True,

View File

@ -107,7 +107,8 @@ class Migration(migrations.Migration):
[
'CREATE INDEX journal_event_timestamp_id_idx ON journal_event USING BRIN("timestamp", "id");',
'CREATE INDEX journal_event_reference_ids_idx ON journal_event USING GIN("reference_ids");',
'CREATE INDEX journal_event_reference_ct_ids_idx ON journal_event USING GIN("reference_ct_ids");',
'CREATE INDEX journal_event_reference_ct_ids_idx ON journal_event USING'
' GIN("reference_ct_ids");',
],
[
'DROP INDEX journal_event_reference_ct_ids_idx;',

View File

@ -85,8 +85,8 @@ class SearchEngine:
@classmethod
def documentation(cls):
yield _(
'You can use colon terminated prefixes to make special searches, '
'and you can use quote around the suffix to preserve spaces.'
'You can use colon terminated prefixes to make special searches, and you can use quote around the'
' suffix to preserve spaces.'
)
for name in dir(cls):
documentation = getattr(getattr(cls, name), 'documentation', None)

View File

@ -35,7 +35,7 @@ def get_field_refs(format_string):
yield field_ref
UNEXPECTED_KEYS_ERROR = '{0}: unexpected ' 'key(s) {1} in configuration'
UNEXPECTED_KEYS_ERROR = '{0}: unexpected key(s) {1} in configuration'
FORMAT_STRING_ERROR = '{0}: template string must contain only keyword references: {1}'
BAD_CONFIG_ERROR = 'template attribute source must contain a name and at least a template'
TYPE_ERROR = 'template attribute must be a string'

View File

@ -61,7 +61,9 @@ class Migration(migrations.Migration):
'is_superuser',
models.BooleanField(
default=False,
help_text='Designates that this user has all permissions without explicitly assigning them.',
help_text=(
'Designates that this user has all permissions without explicitly assigning them.'
),
verbose_name='superuser status',
),
),
@ -92,7 +94,10 @@ class Migration(migrations.Migration):
'is_active',
models.BooleanField(
default=True,
help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.',
help_text=(
'Designates whether this user should be treated as active. Unselect this instead'
' of deleting accounts.'
),
verbose_name='active',
),
),
@ -103,7 +108,10 @@ class Migration(migrations.Migration):
to='auth.Group',
verbose_name='groups',
blank=True,
help_text='The groups this user belongs to. A user will get all permissions granted to each of his/her group.',
help_text=(
'The groups this user belongs to. A user will get all permissions granted to each'
' of his/her group.'
),
related_name='+',
related_query_name='+',
),

View File

@ -13,7 +13,10 @@ class Migration(migrations.Migration):
model_name='user',
name='username',
field=models.CharField(
help_text='Required, 255 characters or fewer. Only letters, numbers, and @, ., +, -, or _ characters.',
help_text=(
'Required, 255 characters or fewer. Only letters, numbers, and @, ., +, -, or _'
' characters.'
),
unique=True,
max_length=255,
verbose_name='username',

View File

@ -29,7 +29,9 @@ class Migration(migrations.Migration):
'is_superuser',
models.BooleanField(
default=False,
help_text='Designates that this user has all permissions without explicitly assigning them.',
help_text=(
'Designates that this user has all permissions without explicitly assigning them.'
),
verbose_name='superuser status',
),
),
@ -62,7 +64,10 @@ class Migration(migrations.Migration):
'is_active',
models.BooleanField(
default=True,
help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.',
help_text=(
'Designates whether this user should be treated as active. Unselect this instead'
' of deleting accounts.'
),
verbose_name='active',
),
),
@ -77,7 +82,10 @@ class Migration(migrations.Migration):
related_name='user_set',
to='auth.Group',
blank=True,
help_text='The groups this user belongs to. A user will get all permissions granted to each of his/her group.',
help_text=(
'The groups this user belongs to. A user will get all permissions granted to each'
' of his/her group.'
),
verbose_name='groups',
),
),

View File

@ -46,7 +46,10 @@ class Migration(migrations.Migration):
related_name='user_set',
to='auth.Group',
blank=True,
help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.',
help_text=(
'The groups this user belongs to. A user will get all permissions granted to each of'
' their groups.'
),
verbose_name='groups',
),
),
@ -64,7 +67,8 @@ class Migration(migrations.Migration):
validators=[
django.core.validators.RegexValidator(
'^[\\w.@+-]+$',
'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.',
'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_'
' characters.',
'invalid',
)
],

View File

@ -59,9 +59,7 @@ class Authentic2Authentication(BasicAuthentication):
if not client.has_api_access:
raise AuthenticationFailed('OIDC client does not have access to the API')
if client.identifier_policy not in (client.POLICY_UUID, client.POLICY_PAIRWISE_REVERSIBLE):
raise AuthenticationFailed(
'OIDC Client identifier policy does not allow access to ' 'the API'
)
raise AuthenticationFailed('OIDC Client identifier policy does not allow access to the API')
user = OIDCUser(client)
user.authenticated = True
return (user, True)

View File

@ -315,7 +315,8 @@ def password_policy_control_messages(ctrl, attributes):
'passwordTooShort': _('The password is too short {pwdminlength}.').format(**attributes),
'passwordTooYoung': _('It is too soon to change the password {pwdminage}.').format(**attributes),
'passwordInHistory': _(
'This password is among the last {pwdhistory} password that were used and cannot be used again.'
'This password is among the last {pwdhistory} password that were used and cannot be used'
' again.'
).format(**attributes),
}
messages.append(error2message.get(error, _('Unexpected error {error}').format(error=error)))
@ -330,7 +331,8 @@ def password_policy_control_messages(ctrl, attributes):
messages.append(
ngettext(
'This password expired: this is the last time it can be used.',
'This password expired and can only be used {graceAuthNsRemaining} times, including this one.',
'This password expired and can only be used {graceAuthNsRemaining} times, including this'
' one.',
ctrl.graceAuthNsRemaining,
).format(graceAuthNsRemaining=ctrl.graceAuthNsRemaining)
)
@ -824,8 +826,8 @@ class LDAPBackend:
request.failed_logins.add(user)
else:
log.warning(
'could not rebind after a bind failure, unable to attach '
'the error to the user'
'could not rebind after a bind failure, unable to attach the error to the'
' user'
)
user_login_failure(authz_id)
pass
@ -842,8 +844,8 @@ class LDAPBackend:
return self._return_user(authz_id, password, conn, block)
except ldap.CONNECT_ERROR:
log.error(
'[%s] connection to %r failed, did you forget to declare the TLS certificate '
'in /etc/ldap/ldap.conf ?',
'[%s] connection to %r failed, did you forget to declare the TLS certificate in'
' /etc/ldap/ldap.conf ?',
ldap_uri,
block['url'],
)
@ -875,7 +877,7 @@ class LDAPBackend:
def _parse_simple_config(self):
if len(settings.LDAP_AUTH_SETTINGS) < 2:
raise ImproperlyConfigured(
'In a minimal configuration, you must at least specify ' 'url and user DN'
'In a minimal configuration, you must at least specify url and user DN'
)
return {'url': settings.LDAP_AUTH_SETTINGS[0], 'basedn': settings.LDAP_AUTH_SETTINGS[1]}
@ -1295,14 +1297,14 @@ class LDAPBackend:
].lower()
if extra_attribute_config['loop_over_attribute'] not in attribute_map:
log.debug(
'loop_over_attribute %s not present (or empty) in retrieved user object attributes. Pass.'
% extra_attribute_config['loop_over_attribute']
'loop_over_attribute %s not present (or empty) in retrieved user object attributes.'
' Pass.' % extra_attribute_config['loop_over_attribute']
)
continue
if 'filter' not in extra_attribute_config and 'basedn' not in extra_attribute_config:
log.warning(
'Extra attribute %s not correctly configured : you need to defined at least one of filter or basedn parameters'
% extra_attribute_name
'Extra attribute %s not correctly configured : you need to defined at least one of'
' filter or basedn parameters' % extra_attribute_name
)
for item in attribute_map[extra_attribute_config['loop_over_attribute']]:
ldap_filter = extra_attribute_config.get('filter', 'objectClass=*').format(
@ -1685,8 +1687,8 @@ class LDAPBackend:
conn.start_tls_s()
except ldap.CONNECT_ERROR:
log.error(
'connection to %r failed when activating TLS, did you forget '
'to declare the TLS certificate in /etc/ldap/ldap.conf ?',
'connection to %r failed when activating TLS, did you forget to declare the TLS'
' certificate in /etc/ldap/ldap.conf ?',
url,
)
continue
@ -1695,8 +1697,8 @@ class LDAPBackend:
continue
except ldap.CONNECT_ERROR:
log.error(
'connection to %r failed when activating TLS, did you forget to '
'declare the TLS certificate in /etc/ldap/ldap.conf ?',
'connection to %r failed when activating TLS, did you forget to declare the TLS'
' certificate in /etc/ldap/ldap.conf ?',
url,
)
continue

View File

@ -608,8 +608,8 @@ class UserCsvImporter:
Error(
'unique-constraint-failed',
_(
'Unique constraint on column "%(column)s" failed: '
'value already appear on line %(line)d'
'Unique constraint on column "%(column)s" failed: value already appear on'
' line %(line)d'
)
% {'column': header.name, 'line': unique_map[unique_key]},
)

View File

@ -51,23 +51,29 @@ def copy_old_users_to_custom_user_model(apps, schema_editor):
# Reset sequences
if schema_editor.connection.vendor == 'postgresql':
schema_editor.execute(
'SELECT setval(pg_get_serial_sequence(\'"custom_user_user_groups"\',\'id\'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "custom_user_user_groups";'
'SELECT setval(pg_get_serial_sequence(\'"custom_user_user_groups"\',\'id\'), coalesce(max("id"),'
' 1), max("id") IS NOT null) FROM "custom_user_user_groups";'
)
schema_editor.execute(
'SELECT setval(pg_get_serial_sequence(\'"custom_user_user_user_permissions"\',\'id\'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "custom_user_user_user_permissions";'
'SELECT setval(pg_get_serial_sequence(\'"custom_user_user_user_permissions"\',\'id\'),'
' coalesce(max("id"), 1), max("id") IS NOT null) FROM "custom_user_user_user_permissions";'
)
schema_editor.execute(
'SELECT setval(pg_get_serial_sequence(\'"custom_user_user"\',\'id\'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "custom_user_user";'
'SELECT setval(pg_get_serial_sequence(\'"custom_user_user"\',\'id\'), coalesce(max("id"), 1),'
' max("id") IS NOT null) FROM "custom_user_user";'
)
elif schema_editor.connection.vendor == 'sqlite':
schema_editor.execute(
'UPDATE sqlite_sequence SET seq = (SELECT MAX(id) FROM custom_user_user) WHERE name = "custom_user_user";'
'UPDATE sqlite_sequence SET seq = (SELECT MAX(id) FROM custom_user_user) WHERE name ='
' "custom_user_user";'
)
schema_editor.execute(
'UPDATE sqlite_sequence SET seq = (SELECT MAX(id) FROM custom_user_user_groups) WHERE name = "custom_user_user_groups";'
'UPDATE sqlite_sequence SET seq = (SELECT MAX(id) FROM custom_user_user_groups) WHERE name ='
' "custom_user_user_groups";'
)
schema_editor.execute(
'UPDATE sqlite_sequence SET seq = (SELECT MAX(id) FROM custom_user_user_user_permissions) WHERE name = "custom_user_user_permissions";'
'UPDATE sqlite_sequence SET seq = (SELECT MAX(id) FROM custom_user_user_user_permissions) WHERE'
' name = "custom_user_user_permissions";'
)
else:
raise NotImplementedError()
@ -96,7 +102,9 @@ class Migration(migrations.Migration):
'is_superuser',
models.BooleanField(
default=False,
help_text='Designates that this user has all permissions without explicitly assigning them.',
help_text=(
'Designates that this user has all permissions without explicitly assigning them.'
),
verbose_name='superuser status',
),
),
@ -137,7 +145,10 @@ class Migration(migrations.Migration):
'is_active',
models.BooleanField(
default=True,
help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.',
help_text=(
'Designates whether this user should be treated as active. Unselect this instead'
' of deleting accounts.'
),
verbose_name='active',
),
),
@ -152,7 +163,10 @@ class Migration(migrations.Migration):
related_name='user_set',
to='auth.Group',
blank=True,
help_text='The groups this user belongs to. A user will get all permissions granted to each of his/her group.',
help_text=(
'The groups this user belongs to. A user will get all permissions granted to each'
' of his/her group.'
),
verbose_name='groups',
),
),

View File

@ -8,7 +8,10 @@ class Migration(migrations.Migration):
operations = [
migrations.RunSQL(
sql=r'CREATE INDEX "custom_user_user_email_idx" ON "custom_user_user" (UPPER("email") text_pattern_ops);',
sql=(
r'CREATE INDEX "custom_user_user_email_idx" ON "custom_user_user" (UPPER("email")'
r' text_pattern_ops);'
),
reverse_sql=r'DROP INDEX "custom_user_user_email_idx";',
),
]

View File

@ -8,7 +8,10 @@ class Migration(migrations.Migration):
operations = [
migrations.RunSQL(
sql=r'CREATE INDEX "custom_user_user_username_idx" ON "custom_user_user" (UPPER("username") text_pattern_ops);',
sql=(
r'CREATE INDEX "custom_user_user_username_idx" ON "custom_user_user" (UPPER("username")'
r' text_pattern_ops);'
),
reverse_sql=r'DROP INDEX "custom_user_user_username_idx";',
),
]

View File

@ -60,8 +60,8 @@ class Migration(migrations.Migration):
TrigramExtension(),
RunSQLIfExtension(
sql=[
"CREATE INDEX IF NOT EXISTS custom_user_user_email_trgm_idx ON custom_user_user USING gist "
"(LOWER(email) public.gist_trgm_ops)"
"CREATE INDEX IF NOT EXISTS custom_user_user_email_trgm_idx ON custom_user_user USING gist"
" (LOWER(email) public.gist_trgm_ops)"
],
reverse_sql=['DROP INDEX custom_user_user_email_trgm_idx'],
),

View File

@ -152,14 +152,14 @@ class User(AbstractBaseUser, PermissionMixin):
is_staff = models.BooleanField(
_('staff status'),
default=False,
help_text=_('Designates whether the user can log into this admin ' 'site.'),
help_text=_('Designates whether the user can log into this admin site.'),
)
is_active = models.BooleanField(
_('active'),
default=True,
help_text=_(
'Designates whether this user should be treated as '
'active. Unselect this instead of deleting accounts.'
'Designates whether this user should be treated as active. Unselect this instead of deleting'
' accounts.'
),
)
ou = models.ForeignKey(
@ -241,8 +241,8 @@ class User(AbstractBaseUser, PermissionMixin):
if not (self.username or self.email or (self.first_name and self.last_name)):
raise ValidationError(
_(
'An account needs at least one identifier: '
'username, email or a full name (first and last name).'
'An account needs at least one identifier: username, email or a full name (first and last'
' name).'
)
)
@ -296,7 +296,7 @@ class User(AbstractBaseUser, PermissionMixin):
pass
else:
errors.setdefault('email', []).append(
_('This email address is already in use. Please supply a different email ' 'address.')
_('This email address is already in use. Please supply a different email address.')
)
if errors:
raise ValidationError(errors)

View File

@ -93,9 +93,8 @@ class AuthenticationForm(auth_forms.AuthenticationForm):
if seconds_to_wait > app_settings.A2_LOGIN_EXPONENTIAL_RETRY_TIMEOUT_MIN_DURATION:
seconds_to_wait -= app_settings.A2_LOGIN_EXPONENTIAL_RETRY_TIMEOUT_MIN_DURATION
msg = _(
'You made too many login errors recently, you must '
'wait <span class="js-seconds-until">%s</span> seconds '
'to try again.'
'You made too many login errors recently, you must wait <span'
' class="js-seconds-until">%s</span> seconds to try again.'
)
msg = msg % int(math.ceil(seconds_to_wait))
msg = html.mark_safe(msg)

View File

@ -114,7 +114,7 @@ class RegistrationCompletionFormNoPassword(profile_forms.BaseUserForm):
exist = True
if exist:
raise ValidationError(
_('This username is already in ' 'use. Please supply a different username.')
_('This username is already in use. Please supply a different username.')
)
return username
@ -133,7 +133,7 @@ class RegistrationCompletionFormNoPassword(profile_forms.BaseUserForm):
exist = True
if exist:
raise ValidationError(
_('This email address is already in ' 'use. Please supply a different email address.')
_('This email address is already in use. Please supply a different email address.')
)
return BaseUserManager.normalize_email(email)

View File

@ -304,8 +304,8 @@ class CheckPasswordInput(PasswordInput):
class ProfileImageInput(ClearableFileInput):
if django.VERSION < (1, 9):
template_with_initial = (
'%(initial_text)s: <a href="%(initial_url)s"><img src="%(initial_url)s"/></a> '
'%(clear_template)s<br />%(input_text)s: %(input)s'
'%(initial_text)s: <a href="%(initial_url)s"><img src="%(initial_url)s"/></a>'
' %(clear_template)s<br />%(input_text)s: %(input)s'
)
else:
template_name = "authentic2/profile_image_input.html"

View File

@ -57,9 +57,10 @@ def check_authentic2_config(app_configs, **kwargs):
errors.append(
Warning(
'You should not use default SAML keys in production',
hint='Generate new RSA keys and change the value of '
'A2_IDP_SAML2_SIGNATURE_PUBLIC_KEY and '
'A2_IDP_SAML2_SIGNATURE_PRIVATE_KEY in your setting file',
hint=(
'Generate new RSA keys and change the value of A2_IDP_SAML2_SIGNATURE_PUBLIC_KEY and'
' A2_IDP_SAML2_SIGNATURE_PRIVATE_KEY in your setting file'
),
)
)
return errors

View File

@ -487,8 +487,7 @@ def build_assertion(request, login, provider, nid_format='transient'):
kwargs['entity_id'] = login.remoteProviderId
kwargs['user'] = request.user
logger.debug(
'sending nameID %(name_id_format)r: %(name_id_content)r to '
'%(entity_id)s for user %(user)s' % kwargs
'sending nameID %(name_id_format)r: %(name_id_content)r to %(entity_id)s for user %(user)s' % kwargs
)
register_new_saml2_session(request, login)
add_attributes(request, entity_id, assertion, provider, nid_format)
@ -529,7 +528,7 @@ def sso(request):
break
except (lasso.ProfileInvalidMsgError, lasso.ProfileMissingIssuerError) as e:
logger.warning(
'invalid message for WebSSO profile with HTTP-Redirect binding: ' '%r exception: %s',
'invalid message for WebSSO profile with HTTP-Redirect binding: %r exception: %s',
message,
e,
extra={'request': request},
@ -541,8 +540,8 @@ def sso(request):
except lasso.ProfileInvalidProtocolprofileError:
log_info_authn_request_details(login)
message = _(
"SAMLv2 Single Sign On: the request cannot be "
"answered because no valid protocol binding could be found"
"SAMLv2 Single Sign On: the request cannot be answered because no valid protocol binding"
" could be found"
)
logger.warning('the request cannot be answered because no valid protocol binding could be found')
return HttpResponseBadRequest(message, content_type='text/plain')
@ -1245,9 +1244,8 @@ def build_session_dump(liberty_sessions):
]
for liberty_session in liberty_sessions:
session.append(
'<NidAndSessionIndex ProviderID="{0.provider_id}" '
'AssertionID="xxx" '
'SessionIndex="{0.session_index}">'.format(liberty_session)
'<NidAndSessionIndex ProviderID="{0.provider_id}" AssertionID="xxx"'
' SessionIndex="{0.session_index}">'.format(liberty_session)
)
session.append(f'<saml:NameID Format="{liberty_session.name_id_format}" ')
if liberty_session.name_id_qualifier:

View File

@ -476,8 +476,8 @@ class Command(BaseCommand):
or (admin_permission.target == admin_role)
):
self.warning(
'invalid admin role "%s" invalid permission "%s": '
'not admin_scope and not self manage permission',
'invalid admin role "%s" invalid permission "%s": not admin_scope and not self manage'
' permission',
admin_role,
admin_permission,
)

View File

@ -123,7 +123,7 @@ class Command(BaseCommand):
parser.add_argument(
'--password',
default='userPassword',
help='attribute to extract the password from, ' 'OpenLDAP hashing algorithm are recognized',
help='attribute to extract the password from, OpenLDAP hashing algorithm are recognized',
)
parser.add_argument('--object-class', default='inetOrgPerson', help='object class of records to load')
parser.add_argument(
@ -139,8 +139,10 @@ class Command(BaseCommand):
parser.add_argument(
'--callback',
default=None,
help='python file containing a function callback(user, dn, entry, options, dump)'
' it can return models that will be saved',
help=(
'python file containing a function callback(user, dn, entry, options, dump) it can return'
' models that will be saved'
),
)
parser.add_argument('--callback-arg', action='append', help='arguments for the callback')

View File

@ -63,6 +63,6 @@ class Command(BaseCommand):
u.save()
PasswordReset.objects.get_or_create(user=u)
return (
'Password changed successfully for user "%s", on next login he '
'will be forced to change its password.' % u
'Password changed successfully for user "%s", on next login he will be forced to change its'
' password.' % u
)

View File

@ -228,7 +228,7 @@ class UserChangePasswordForm(CssClass, forms.ModelForm):
and not self.cleaned_data.get('send_password_reset')
):
raise forms.ValidationError(
_('You must choose password generation or type a new' ' one or send a password reset mail')
_('You must choose password generation or type a new one or send a password reset mail')
)
if not self.has_email() and (
self.cleaned_data.get('send_mail')
@ -236,7 +236,7 @@ class UserChangePasswordForm(CssClass, forms.ModelForm):
or self.cleaned_data.get('send_password_reset')
):
raise forms.ValidationError(
_('User does not have a mail, we cannot send the ' 'informations to him.')
_('User does not have a mail, we cannot send the informations to him.')
)
def has_email(self):
@ -347,7 +347,7 @@ class UserAddForm(UserChangePasswordForm, UserEditForm):
)
except smtplib.SMTPException as e:
logger.error(
'registration mail could not be sent to user %s created through ' 'manager: %s', user, e
'registration mail could not be sent to user %s created through manager: %s', user, e
)
return user

View File

@ -243,7 +243,8 @@ class ManagerUserDeactivation(EventTypeDefinition):
elif user:
if reason == LDAP_DEACTIVATION_REASON_NOT_PRESENT:
return _(
'automatic deactivation of user "%s" because the associated LDAP account does not exist anymore'
'automatic deactivation of user "%s" because the associated LDAP account does not exist'
' anymore'
) % user_to_str(user)
elif reason == LDAP_DEACTIVATION_REASON_OLD_SOURCE:
return _(

View File

@ -99,10 +99,8 @@ class OrganizationalUnitDeleteView(views.BaseDeleteView):
messages.warning(
request,
_(
'You cannot delete the default '
'organizational unit, you must first '
'set another default organiational '
'unit.'
'You cannot delete the default organizational unit, you must first set another default'
' organiational unit.'
),
)
return self.return_ajax_response(request, HttpResponseRedirect(self.get_success_url()))

View File

@ -73,7 +73,7 @@ class ServiceView(
if self.can_change:
if action == 'add':
if self.object.authorized_roles.filter(pk=role.pk).exists():
messages.warning(self.request, _('Role already authorized in this ' 'service.'))
messages.warning(self.request, _('Role already authorized in this service.'))
else:
self.object.add_authorized_role(role)
elif action == 'remove':

View File

@ -88,9 +88,8 @@ class UserTable(tables.Table):
class RoleMembersTable(UserTable):
direct = tables.BooleanColumn(verbose_name=_('Direct member'), orderable=False)
via = tables.TemplateColumn(
'{% for role in record.via %}'
'<a href="{% url "a2-manager-role-members" pk=role.pk %}">{{ role }}</a>{% if not forloop.last %}, {% endif %}'
'{% endfor %}',
'{% for role in record.via %}<a href="{% url "a2-manager-role-members" pk=role.pk %}">{{ role'
' }}</a>{% if not forloop.last %}, {% endif %}{% endfor %}',
verbose_name=_('Inherited from'),
orderable=False,
)
@ -151,13 +150,10 @@ class OuUserRolesTable(tables.Table):
orderable=False,
)
member = tables.TemplateColumn(
'{%% load i18n %%}<input class="role-member{%% if not record.member and record.via %%} '
'indeterminate{%% endif %%}"'
' name="role-{{ record.pk }}" type="checkbox" {%% if record.member %%}checked{%% endif %%} '
'{%% if not record.has_perm %%}disabled '
'title="{%% trans "%s" %%}"{%% endif %%} '
'{%% if not record.can_manage_members %%}disabled '
'title="{%% trans "%s" %%}"{%% endif %%}/>'
'{%% load i18n %%}<input class="role-member{%% if not record.member and record.via %%}'
' indeterminate{%% endif %%}" name="role-{{ record.pk }}" type="checkbox" {%% if record.member'
' %%}checked{%% endif %%} {%% if not record.has_perm %%}disabled title="{%% trans "%s" %%}"{%% endif'
' %%} {%% if not record.can_manage_members %%}disabled title="{%% trans "%s" %%}"{%% endif %%}/>'
% (
ugettext_noop('You are not authorized to manage this role'),
ugettext_noop('This role is synchronised from LDAP, changing members is not allowed.'),
@ -186,9 +182,8 @@ class UserRolesTable(tables.Table):
)
ou = tables.Column()
via = tables.TemplateColumn(
'{% if not record.member %}{% for rel in record.child_relation.all %}'
'{{ rel.child }} {% if not forloop.last %}, {% endif %}{% endfor %}'
'{% endif %}',
'{% if not record.member %}{% for rel in record.child_relation.all %}{{ rel.child }} {% if not'
' forloop.last %}, {% endif %}{% endfor %}{% endif %}',
verbose_name=_('Inherited from'),
orderable=False,
)

View File

@ -128,7 +128,7 @@ class UsersView(HideOUColumnMixin, BaseTableView):
table = super().get_table(**kwargs)
if self.search_form.not_enough_chars():
user_qs = self.search_form.filter_by_ou(self.get_queryset())
table.empty_text = _('Enter at least %(limit)d characters ' '(%(user_count)d users)') % {
table.empty_text = _('Enter at least %(limit)d characters (%(user_count)d users)') % {
'limit': self.search_form.minimum_chars,
'user_count': user_qs.count(),
}
@ -323,7 +323,7 @@ class UserDetailView(OtherActionsMixin, BaseDetailView):
else:
yield Action(
'force_password_change',
_('Force password change on ' 'next login'),
_('Force password change on next login'),
permission='custom_user.reset_password_user',
)
yield Action(
@ -353,7 +353,7 @@ class UserDetailView(OtherActionsMixin, BaseDetailView):
def action_deactivate(self, request, *args, **kwargs):
if request.user == self.object:
messages.warning(request, _('You cannot desactivate your own ' 'user'))
messages.warning(request, _('You cannot desactivate your own user'))
else:
self.object.mark_as_inactive()
request.journal.record('manager.user.deactivation', target_user=self.object)
@ -363,7 +363,7 @@ class UserDetailView(OtherActionsMixin, BaseDetailView):
if not user.email:
messages.info(
request,
_('User has no email, it\'not possible to ' 'send him am email to reset its ' 'password'),
_('User has no email, it\'not possible to send him am email to reset its password'),
)
return
send_password_reset_mail(user, request=request)

View File

@ -552,7 +552,7 @@ class BaseAddView(
@property
def title(self):
return ('Add %s') % super().get_model_name()
return 'Add %s' % super().get_model_name()
def get_success_url(self):
return reverse(self.success_view_name, kwargs={'pk': self.object.pk})

View File

@ -136,7 +136,10 @@ class Migration(migrations.Migration):
(
'logout_url',
models.URLField(
help_text='you can use a {} to pass the URL of the success icon, ex.: http://example.com/logout?next={}',
help_text=(
'you can use a {} to pass the URL of the success icon, ex.:'
' http://example.com/logout?next={}'
),
max_length=255,
null=True,
verbose_name='url',
@ -153,7 +156,10 @@ class Migration(migrations.Migration):
'logout_use_iframe_timeout',
models.PositiveIntegerField(
default=300,
help_text="if iframe logout is used, it's the time between the onload event for this iframe and the moment we consider its loading to be really finished",
help_text=(
"if iframe logout is used, it's the time between the onload event for this iframe"
" and the moment we consider its loading to be really finished"
),
verbose_name='iframe logout timeout (ms)',
),
),

View File

@ -13,10 +13,10 @@ class Migration(migrations.Migration):
sql=[
"CREATE EXTENSION IF NOT EXISTS unaccent SCHEMA public",
"CREATE EXTENSION IF NOT EXISTS pg_trgm SCHEMA public",
"CREATE OR REPLACE FUNCTION public.immutable_unaccent(text) RETURNS varchar AS $$ "
"SELECT public.unaccent('public.unaccent',$1::text); $$ LANGUAGE 'sql' IMMUTABLE",
"CREATE INDEX custom_user_name_gist_idx ON custom_user_user USING gist "
"(LOWER(public.immutable_unaccent(first_name || ' ' || last_name)) public.gist_trgm_ops)",
"CREATE OR REPLACE FUNCTION public.immutable_unaccent(text) RETURNS varchar AS $$ SELECT"
" public.unaccent('public.unaccent',$1::text); $$ LANGUAGE 'sql' IMMUTABLE",
"CREATE INDEX custom_user_name_gist_idx ON custom_user_user USING gist"
" (LOWER(public.immutable_unaccent(first_name || ' ' || last_name)) public.gist_trgm_ops)",
],
reverse_sql=[
"DROP INDEX IF EXISTS custom_user_name_gist_idx",

View File

@ -11,9 +11,8 @@ def clean_admin_tools_tables(apps, schema_editor):
try:
with schema_editor.connection.cursor() as cursor:
cursor.execute(
"SELECT table_name FROM information_schema.tables "
"WHERE table_schema = current_schema() "
"AND table_name LIKE 'admin_tools%'"
"SELECT table_name FROM information_schema.tables WHERE table_schema = current_schema() AND"
" table_name LIKE 'admin_tools%'"
)
rows = cursor.fetchall()
for (table_name,) in rows:

View File

@ -27,7 +27,8 @@ FOR EACH ROW EXECUTE PROCEDURE authentic2_update_atv_search_vector()'''
def drop_trigger(apps, schema_editor):
with schema_editor.connection.cursor() as cursor:
cursor.execute(
'DROP TRIGGER IF EXISTS authentic2_attributevalue_search_vector_trigger ON authentic2_attributevalue'
'DROP TRIGGER IF EXISTS authentic2_attributevalue_search_vector_trigger ON'
' authentic2_attributevalue'
)
cursor.execute('DROP FUNCTION IF EXISTS authentic2_update_atv_search_vector')

View File

@ -59,7 +59,7 @@ class UserExternalId(models.Model):
return f'{self.user} is {self.external_id} on {self.source}'
def __repr__(self):
return '<UserExternalId user: {!r} source: {!r} ' 'external_id: {!r} created: {} updated: {}'.format(
return '<UserExternalId user: {!r} source: {!r} external_id: {!r} created: {} updated: {}'.format(
self.user_id, self.source, self.external_id, self.created, self.updated
)
@ -93,7 +93,7 @@ class LogoutUrlAbstract(models.Model):
logout_url = models.URLField(
verbose_name=_('url'),
help_text=_(
'you can use a {} to pass the URL of the success icon, ' 'ex.: http://example.com/logout?next={}'
'you can use a {} to pass the URL of the success icon, ex.: http://example.com/logout?next={}'
),
max_length=255,
blank=True,
@ -105,9 +105,8 @@ class LogoutUrlAbstract(models.Model):
logout_use_iframe_timeout = models.PositiveIntegerField(
verbose_name=_('iframe logout timeout (ms)'),
help_text=_(
'if iframe logout is used, it\'s the time between the '
'onload event for this iframe and the moment we consider its '
'loading to be really finished'
'if iframe logout is used, it\'s the time between the onload event for this iframe and the moment'
' we consider its loading to be really finished'
),
default=300,
)

View File

@ -125,9 +125,9 @@ def password_help_text(password='', only_errors=False):
if criteria:
html_criteria = ['<span class="a2-password-policy-rule">%s</span>' % criter for criter in criteria]
return _(
'In order to create a secure password, please use at least: '
'<span class="a2-password-policy-container">%s</span>'
) % (''.join(html_criteria))
'In order to create a secure password, please use at least: <span'
' class="a2-password-policy-container">%s</span>'
) % ''.join(html_criteria)
else:
return ''

View File

@ -103,7 +103,7 @@ def update_metadata(modeladmin, request, queryset):
provider.update_metadata()
except ValidationError as e:
params = {'name': provider, 'error_msg': ', '.join(e.messages)}
messages.error(request, _('Updating SAML provider %(name)s failed: ' '%(error_msg)s') % params)
messages.error(request, _('Updating SAML provider %(name)s failed: %(error_msg)s') % params)
else:
count += 1
messages.info(

View File

@ -247,7 +247,7 @@ def check_id_and_issue_instant(request_response_or_assertion, now=None):
logger.warning('missing ID')
return False
if not nonce.accept_nonce(_id, 'SAML', 2 * NONCE_TIMEOUT):
logger.warning("ID '%r' already used, request/response/assertion " "refused", _id)
logger.warning("ID '%r' already used, request/response/assertion refused", _id)
return False
return True
@ -332,7 +332,7 @@ def retrieve_metadata_and_create(request, provider_id, sp_or_idp):
metadata = get_url(provider_id)
except Exception as e:
logging.error(
'SAML metadata autoload: failure to retrieve metadata ' 'for entity id %s: %s', provider_id, e
'SAML metadata autoload: failure to retrieve metadata for entity id %s: %s', provider_id, e
)
return None
logger.debug('loaded %d bytes', len(metadata))
@ -346,15 +346,13 @@ def retrieve_metadata_and_create(request, provider_id, sp_or_idp):
p.full_clean(exclude=['entity_id', 'protocol_conformance'])
except ValidationError as e:
logging.error(
'SAML metadata autoload: retrieved metadata for entity ' 'id %s are invalid, %s',
'SAML metadata autoload: retrieved metadata for entity id %s are invalid, %s',
provider_id,
e.args,
)
return None
except Exception:
logging.exception(
'SAML metadata autoload: retrieved metadata ' 'validation raised an unknown exception'
)
logging.exception('SAML metadata autoload: retrieved metadata validation raised an unknown exception')
return None
p.save()
logger.debug('%s saved', p)
@ -581,8 +579,8 @@ def get_session_not_on_or_after(assertion):
session_not_on_or_afters.append(saml2utils.iso8601_to_datetime(value))
except ValueError:
logging.getLogger(__name__).error(
'unable to parse SessionNotOnOrAfter value %s, will '
'use default value for session length.',
'unable to parse SessionNotOnOrAfter value %s, will use default value for session'
' length.',
value,
)
if session_not_on_or_afters:

View File

@ -2061,7 +2061,9 @@ ATTRIBUTE_MAPPING = {
# macedir .org or eduGain
"schacHomeOrganizationType": {
"oid": "1.3.6.1.4.1.25178.1.2.10",
"display_name": "Identifies the type of organisation specified in the person's schacHomeOrganization attribute.",
"display_name": (
"Identifies the type of organisation specified in the person's schacHomeOrganization attribute."
),
"type": "http://www.w3.org/2001/XMLSchema#string",
"syntax": "1.3.6.1.4.1.1466.115.121.1.15",
},

View File

@ -283,24 +283,29 @@ class Command(BaseCommand):
'--source',
dest='source',
default=None,
help='Tag the loaded providers with the given source string, '
'existing providers with the same tag will be removed if they do not exist '
'anymore in the metadata file.',
help=(
'Tag the loaded providers with the given source string, existing providers with the same tag'
' will be removed if they do not exist anymore in the metadata file.'
),
)
parser.add_argument(
'--reset-attributes',
action='store_true',
default=False,
help='When loading shibboleth attribute filter policies, start by '
'removing all existing SAML attributes for each provider',
help=(
'When loading shibboleth attribute filter policies, start by removing all existing SAML'
' attributes for each provider'
),
)
parser.add_argument(
'--dont-load-attribute-consuming-service',
dest='load_attribute_consuming_service',
default=True,
action='store_false',
help='Prevent loading of the attribute policy from '
'AttributeConsumingService nodes in the metadata file.',
help=(
'Prevent loading of the attribute policy from AttributeConsumingService nodes in the metadata'
' file.'
),
)
parser.add_argument(
'--shibboleth-attribute-filter-policy',
@ -367,14 +372,13 @@ Any other kind of attribute filter policy is unsupported.
sp_policy = SPOptionsIdPPolicy.objects.get(name=sp_policy_name)
if verbosity > 1:
print(
'Service providers are set with the following SAML2 \
options policy: %s'
% sp_policy
'Service providers are set with the following SAML2 '
' options policy: %s' % sp_policy
)
except SPOptionsIdPPolicy.DoesNoextExist:
if verbosity > 0:
print(
_('SAML2 service provider options ' 'policy with name %s not found')
_('SAML2 service provider options policy with name %s not found')
% sp_policy_name,
file=sys.stderr,
)

View File

@ -115,7 +115,10 @@ class Migration(migrations.Migration):
'transient_is_persistent',
models.BooleanField(
default=False,
verbose_name='This IdP sends a transient NameID but you want a persistent behaviour for your SP',
verbose_name=(
'This IdP sends a transient NameID but you want a persistent behaviour for'
' your SP'
),
),
),
(
@ -132,7 +135,10 @@ class Migration(migrations.Migration):
'enable_binding_for_sso_response',
models.BooleanField(
default=False,
verbose_name='Binding for Authnresponse (taken from metadata by the IdP if not enabled)',
verbose_name=(
'Binding for Authnresponse (taken from metadata by the IdP if not'
' enabled)'
),
),
),
(
@ -151,7 +157,10 @@ class Migration(migrations.Migration):
'enable_http_method_for_slo_request',
models.BooleanField(
default=False,
verbose_name='HTTP method for single logout request (taken from metadata if not enabled)',
verbose_name=(
'HTTP method for single logout request (taken from metadata if not'
' enabled)'
),
),
),
(
@ -167,7 +176,10 @@ class Migration(migrations.Migration):
'enable_http_method_for_defederation_request',
models.BooleanField(
default=False,
verbose_name='HTTP method for federation termination request (taken from metadata if not enabled)',
verbose_name=(
'HTTP method for federation termination request (taken from metadata'
' if not enabled)'
),
),
),
(
@ -382,14 +394,20 @@ class Migration(migrations.Migration):
'enable_following_idp_options_policy',
models.BooleanField(
default=False,
verbose_name='The following options policy will apply except if a policy for all identity provider is defined.',
verbose_name=(
'The following options policy will apply except if a policy for all identity'
' provider is defined.'
),
),
),
(
'enable_following_authorization_policy',
models.BooleanField(
default=False,
verbose_name='The following authorization policy will apply except if a policy for all identity provider is defined.',
verbose_name=(
'The following authorization policy will apply except if a policy for all'
' identity provider is defined.'
),
),
),
(
@ -439,14 +457,20 @@ class Migration(migrations.Migration):
'enable_following_sp_options_policy',
models.BooleanField(
default=False,
verbose_name='The following options policy will apply except if a policy for all service provider is defined.',
verbose_name=(
'The following options policy will apply except if a policy for all service'
' provider is defined.'
),
),
),
(
'enable_following_attribute_policy',
models.BooleanField(
default=False,
verbose_name='The following attribute policy will apply except if a policy for all service provider is defined.',
verbose_name=(
'The following attribute policy will apply except if a policy for all service'
' provider is defined.'
),
),
),
(
@ -658,7 +682,10 @@ class Migration(migrations.Migration):
'needs_iframe_logout',
models.BooleanField(
default=False,
help_text='logout URL are normally loaded inside an <img> HTML tag, some service provider need to use an iframe',
help_text=(
'logout URL are normally loaded inside an <img> HTML tag, some service provider'
' need to use an iframe'
),
verbose_name='needs iframe logout',
),
),
@ -666,7 +693,10 @@ class Migration(migrations.Migration):
'iframe_logout_timeout',
models.PositiveIntegerField(
default=300,
help_text="if iframe logout is used, it's the time between the onload event for this iframe and the moment we consider its loading to be really finished",
help_text=(
"if iframe logout is used, it's the time between the onload event for this iframe"
" and the moment we consider its loading to be really finished"
),
verbose_name='iframe logout timeout',
),
),

View File

@ -265,16 +265,16 @@ class SPOptionsIdPPolicy(models.Model):
needs_iframe_logout = models.BooleanField(
verbose_name=_('needs iframe logout'),
help_text=_(
'logout URL are normally loaded inside an <img> HTML tag, some service provider need to use an iframe'
'logout URL are normally loaded inside an <img> HTML tag, some service provider need to use an'
' iframe'
),
default=False,
)
iframe_logout_timeout = models.PositiveIntegerField(
verbose_name=_('iframe logout timeout'),
help_text=_(
'if iframe logout is used, it\'s the time between the '
'onload event for this iframe and the moment we consider its '
'loading to be really finished'
'if iframe logout is used, it\'s the time between the onload event for this iframe and the moment'
' we consider its loading to be really finished'
),
default=300,
)
@ -460,8 +460,7 @@ class LibertyServiceProvider(models.Model):
enabled = models.BooleanField(verbose_name=_('Enabled'), default=False, db_index=True)
enable_following_sp_options_policy = models.BooleanField(
verbose_name=_(
'The following options policy will apply except '
'if a policy for all service provider is defined.'
'The following options policy will apply except if a policy for all service provider is defined.'
),
default=False,
)

View File

@ -355,8 +355,8 @@ def authnresponse_checking(login, subject_confirmation, logger, saml_request_id=
if irt:
if not_before is not None:
logger.error(
'assertion in response to an AuthnRequest, \
notBefore MUST not be present in SubjectConfirmationData'
'assertion in response to an AuthnRequest, notBefore MUST not be present in'
' SubjectConfirmationData'
)
return False
elif not_before is not None and not not_before.endswith('Z'):
@ -381,8 +381,7 @@ def authnresponse_checking(login, subject_confirmation, logger, saml_request_id=
return False
logger.debug(
'assertion validity timeslice respected \
%s <= %s < %s '
'assertion validity timeslice respected %s <= %s < %s '
% (not_before, str(now), not_on_or_after)
)
return True
@ -401,8 +400,7 @@ def get_attributes_from_assertion(assertion, logger):
name = attribute.name.decode('ascii')
except Exception:
logger.warning(
'get_attributes_from_assertion: error decoding name of \
attribute %s'
'get_attributes_from_assertion: error decoding name of attribute %s'
% attribute.dump()
)
else:
@ -412,8 +410,10 @@ def get_attributes_from_assertion(assertion, logger):
if attribute.friendlyName:
nickname = attribute.friendlyName
except Exception as e:
message = 'get_attributes_from_assertion: name or format of an \
attribute failed to decode as ascii: %s due to %s'
message = (
'get_attributes_from_assertion: name or format of an '
' attribute failed to decode as ascii: %s due to %s'
)
logger.warning(message % (attribute.dump(), str(e)))
try:
values = attribute.attributeValue
@ -426,8 +426,10 @@ def get_attributes_from_assertion(assertion, logger):
content = ''.join(content)
attributes[(name, format)].append(content.decode('utf8'))
except Exception as e:
message = 'get_attributes_from_assertion: value of an \
attribute failed to decode as ascii: %s due to %s'
message = (
'get_attributes_from_assertion: value of an attribute failed'
' to decode as ascii: %s due to %s'
)
logger.warning(message % (attribute.dump(), str(e)))
attributes['__issuer'] = assertion.issuer.content
attributes['__nameid'] = assertion.subject.nameID.content

View File

@ -170,12 +170,7 @@ def int_to_cryptobinary(integer):
def get_xmldsig_rsa_key_value(publickey):
mod = get_rsa_public_key_modulus(publickey)
exp = get_rsa_public_key_exponent(publickey)
return (
'<RSAKeyValue xmlns="http://www.w3.org/2000/09/xmldsig#">\n\t'
'<Modulus>%s</Modulus>\n\t'
'<Exponent>%s</Exponent>\n</RSAKeyValue>'
% (
int_to_cryptobinary(mod),
int_to_cryptobinary(exp),
)
return '<RSAKeyValue' ' xmlns="http://www.w3.org/2000/09/xmldsig#">\n\t<Modulus>%s</Modulus>\n\t<Exponent>%s</Exponent>\n</RSAKeyValue>' % (
int_to_cryptobinary(mod),
int_to_cryptobinary(exp),
)

View File

@ -245,7 +245,10 @@ LOGGING = {
},
'formatters': {
'verbose': {
'format': '[%(asctime)s] %(ip)s %(user)s %(request_id)s %(levelname)s %(name)s.%(funcName)s: %(message)s',
'format': (
'[%(asctime)s] %(ip)s %(user)s %(request_id)s %(levelname)s %(name)s.%(funcName)s:'
' %(message)s'
),
'datefmt': '%Y-%m-%d %a %H:%M:%S',
},
'verbose_db': {

View File

@ -154,7 +154,7 @@ def load_backend(path, kwargs):
raise ImproperlyConfigured('Error importing idp backend %s: "%s"' % (module, e))
except ValueError:
raise ImproperlyConfigured(
'Error importing idp backends. Is IDP_BACKENDS a correctly ' 'defined list or tuple?'
'Error importing idp backends. Is IDP_BACKENDS a correctly defined list or tuple?'
)
try:
cls = getattr(mod, attr)
@ -944,7 +944,7 @@ def send_password_reset_mail(
**kwargs,
)
logger.info(
'password reset request for user %s, email sent to %s ' 'with token %s', user, user.email, token.uuid
'password reset request for user %s, email sent to %s with token %s', user, user.email, token.uuid
)

View File

@ -31,7 +31,8 @@ def check_cookie_works(request):
messages.warning(
request,
_(
'Cookies are disabled in your browser, please activate them or you will not be able to log in.'
'Cookies are disabled in your browser, please activate them or you will not be able to'
' log in.'
),
)
return False

View File

@ -208,10 +208,8 @@ class EmailChangeView(cbv.TemplateNamesMixin, FormView):
messages.info(
self.request,
_(
'Your request for changing your email '
'is received. An email of validation '
'was sent to you. Please click on the '
'link contained inside.'
'Your request for changing your email is received. An email of validation was sent to you.'
' Please click on the link contained inside.'
),
)
logger.info('email change request')
@ -726,8 +724,8 @@ class PasswordResetView(FormView):
form.add_error(
'email',
_(
'An email has already been sent to %s. Click "Validate" again if '
'you really want it to be sent again.'
'An email has already been sent to %s. Click "Validate" again if you really want it to be'
' sent again.'
)
% email,
)
@ -745,8 +743,8 @@ class PasswordResetView(FormView):
form.add_error(
'email',
_(
'Multiple emails have already been sent to this address. Further attempts are '
'blocked, please check your spam folder or try again later.'
'Multiple emails have already been sent to this address. Further attempts are blocked,'
' please check your spam folder or try again later.'
),
)
return self.form_invalid(form)
@ -761,8 +759,8 @@ class PasswordResetView(FormView):
form.add_error(
'email',
_(
'Multiple password reset attempts have already been made from this IP address. No '
'further email will be sent, please check your spam folder or try again later.'
'Multiple password reset attempts have already been made from this IP address. No further'
' email will be sent, please check your spam folder or try again later.'
),
)
return self.form_invalid(form)
@ -911,8 +909,8 @@ class BaseRegistrationView(FormView):
form.add_error(
'email',
_(
'An email has already been sent to %s. Click "Validate" again if '
'you really want it to be sent again.'
'An email has already been sent to %s. Click "Validate" again if you really want it to be'
' sent again.'
)
% email,
)
@ -929,8 +927,8 @@ class BaseRegistrationView(FormView):
form.add_error(
'email',
_(
'Multiple emails have already been sent to this address. Further attempts are '
'blocked, please check your spam folder or try again later.'
'Multiple emails have already been sent to this address. Further attempts are blocked,'
' please check your spam folder or try again later.'
),
)
return self.form_invalid(form)
@ -944,8 +942,8 @@ class BaseRegistrationView(FormView):
form.add_error(
'email',
_(
'Multiple registration attempts have already been made from this IP address. No '
'further email will be sent, please check your spam folder or try again later.'
'Multiple registration attempts have already been made from this IP address. No further'
' email will be sent, please check your spam folder or try again later.'
),
)
return self.form_invalid(form)

View File

@ -390,11 +390,10 @@ class LoginOrLinkView(View):
messages.warning(
request,
_(
'Your FranceConnect email address \'%s\' is already used by another '
'account, so we cannot create an account for you. Please connect '
'with you existing account or create an '
'account with another email address then link it to FranceConnect '
'using your account management page.'
'Your FranceConnect email address \'%s\' is already used by another account, so we'
' cannot create an account for you. Please connect with you existing account or'
' create an account with another email address then link it to FranceConnect using'
' your account management page.'
)
% email,
)
@ -403,10 +402,10 @@ class LoginOrLinkView(View):
messages.warning(
request,
_(
'Your FranceConnect email address "%(email)s" is already used by the FranceConnect '
'account of "%(user)s", so we cannot create an account for you. Please create '
'an account with another email address then link it to FranceConnect '
'using your account management page.'
'Your FranceConnect email address "%(email)s" is already used by the FranceConnect'
' account of "%(user)s", so we cannot create an account for you. Please create an'
' account with another email address then link it to FranceConnect using your account'
' management page.'
)
% {'email': email, 'user': user.get_full_name()},
)

View File

@ -59,8 +59,7 @@ class OIDCBackend(ModelBackend):
key_or_keyset = provider.jwkset
if not key_or_keyset:
logger.warning(
'auth_oidc: idtoken signature algorithm is RSA but '
'no JWKSet is defined on provider %s',
'auth_oidc: idtoken signature algorithm is RSA but no JWKSet is defined on provider %s',
id_token.iss,
)
return None
@ -70,8 +69,8 @@ class OIDCBackend(ModelBackend):
key_or_keyset = JWK(kty='oct', k=k.decode('ascii'))
if not provider.client_secret:
logger.warning(
'auth_oidc: idtoken signature algorithm is HMAC but '
'no client_secret is defined on provider %s',
'auth_oidc: idtoken signature algorithm is HMAC but no client_secret is defined on'
' provider %s',
id_token.iss,
)
return None
@ -80,7 +79,7 @@ class OIDCBackend(ModelBackend):
key_or_keyset = provider.jwkset
if not key_or_keyset:
logger.warning(
'auth_oidc: idtoken signature algorithm is EC but ' 'no JWKSet is defined on provider %s',
'auth_oidc: idtoken signature algorithm is EC but no JWKSet is defined on provider %s',
id_token.iss,
)
return None
@ -112,7 +111,7 @@ class OIDCBackend(ModelBackend):
return None
if id_token.azp != provider.client_id:
logger.warning(
'auth_oidc: multiple audience and azp %r does not match client_id' ' %r',
'auth_oidc: multiple audience and azp %r does not match client_id %r',
id_token.azp,
provider.client_id,
)
@ -121,8 +120,7 @@ class OIDCBackend(ModelBackend):
if provider.max_auth_age:
if not id_token.iat:
logger.warning(
'auth_oidc: provider configured for fresh authentication but iat is '
'missing from idtoken'
'auth_oidc: provider configured for fresh authentication but iat is missing from idtoken'
)
return None
duration = now() - id_token.iat
@ -169,9 +167,7 @@ class OIDCBackend(ModelBackend):
user_info = None
if need_user_info:
if not access_token:
logger.warning(
'auth_oidc: need user info for some claims, but no access token was ' 'returned'
)
logger.warning('auth_oidc: need user info for some claims, but no access token was returned')
return None
try:
response = requests.get(
@ -199,14 +195,14 @@ class OIDCBackend(ModelBackend):
logger.warning('claim \'%r\' is templated, it cannot be set as required')
elif claim_mapping.idtoken_claim and claim not in id_token:
logger.warning(
'auth_oidc: cannot create user missing required claim %r in ' 'id_token (%r)',
'auth_oidc: cannot create user missing required claim %r in id_token (%r)',
claim,
id_token,
)
return None
elif not user_info or claim not in user_info:
logger.warning(
'auth_oidc: cannot create user missing required claim %r in ' 'user_info (%r)',
'auth_oidc: cannot create user missing required claim %r in user_info (%r)',
claim,
user_info,
)
@ -269,8 +265,8 @@ class OIDCBackend(ModelBackend):
pass
except User.MultipleObjectsReturned:
logger.error(
'auth_oidc: cannot create user with sub "%s", '
'too many users with the same email "%s" in ou "%s"',
'auth_oidc: cannot create user with sub "%s", too many users with the same email "%s"'
' in ou "%s"',
id_token.sub,
email,
provider.ou,
@ -295,7 +291,7 @@ class OIDCBackend(ModelBackend):
oidc_account.save()
else:
logger.warning(
'auth_oidc: cannot create user for sub %r as issuer %r does not' ' allow it',
'auth_oidc: cannot create user for sub %r as issuer %r does not allow it',
id_token.sub,
id_token.iss,
)

View File

@ -38,7 +38,7 @@ class Command(BaseCommand):
parser.add_argument('name')
parser.add_argument('--issuer', help='do automatic registration of the issuer')
parser.add_argument(
'--openid-configuration', help='file containing the OpenID Connect ' 'configuration of the OP'
'--openid-configuration', help='file containing the OpenID Connect configuration of the OP'
)
parser.add_argument(
'--claim-mapping', default=[], action='append', help='mapping from claim to attribute'
@ -103,7 +103,7 @@ class Command(BaseCommand):
tup = claim_mapping.split()
if len(tup) < 2:
raise CommandError(
'invalid claim mapping %r. it must contain at least a claim and ' 'an attribute name'
'invalid claim mapping %r. it must contain at least a claim and an attribute name'
)
claim, attribute = tup[:2]
claim_options = [x.strip() for x in tup[2:]]

View File

@ -69,7 +69,7 @@ def get_provider_by_issuer(issuer):
def parse_id_token(encoded, provider):
""" May raise any subclass of jwcrypto.common.JWException """
"""May raise any subclass of jwcrypto.common.JWException"""
jwt = JWT()
jwt.deserialize(encoded, None)
header = jwt.token.jose_header
@ -207,7 +207,7 @@ def register_issuer(name, issuer=None, openid_configuration=None, verify=True, t
response.raise_for_status()
except requests.RequestException as e:
raise ValueError(
_('Unable to reach the OpenID Connect configuration for %(issuer)s: ' '%(error)s')
_('Unable to reach the OpenID Connect configuration for %(issuer)s: %(error)s')
% {
'issuer': issuer,
'error': e,
@ -231,15 +231,15 @@ def register_issuer(name, issuer=None, openid_configuration=None, verify=True, t
}
)
except ValueError as e:
raise ValueError(_('Invalid OpenID Connect configuration for %(issuer)s: ' '%(error)s') % (issuer, e))
raise ValueError(_('Invalid OpenID Connect configuration for %(issuer)s: %(error)s') % (issuer, e))
if 'code' not in openid_configuration['response_types_supported']:
raise ValueError(_('authorization code flow is unsupported: code response type is ' 'unsupported'))
raise ValueError(_('authorization code flow is unsupported: code response type is unsupported'))
try:
response = requests.get(openid_configuration['jwks_uri'], verify=verify, timeout=None)
response.raise_for_status()
except requests.RequestException as e:
raise ValueError(
_('Unable to reach the OpenID Connect JWKSet for %(issuer)s: ' '%(url)s %(error)s')
_('Unable to reach the OpenID Connect JWKSet for %(issuer)s: %(url)s %(error)s')
% {
'issuer': issuer,
'url': openid_configuration['jwks_uri'],
@ -289,7 +289,7 @@ def get_openid_configuration_url(issuer):
parsed = urllib.parse.urlparse(issuer)
if parsed.query or parsed.fragment or parsed.scheme != 'https':
raise ValueError(
_('invalid issuer URL, it must use the https:// scheme and not have a ' 'query or fragment')
_('invalid issuer URL, it must use the https:// scheme and not have a query or fragment')
)
issuer = urllib.parse.urlunparse(
(parsed.scheme, parsed.netloc, parsed.path.rstrip('/'), None, None, None)

View File

@ -208,8 +208,8 @@ class LoginCallback(View):
error = None
error_description = None
logger.warning(
'auth_oidc: token_endpoint returned HTTP error status '
'%(status_code)s for %(issuer)s with content %(content)s'
'auth_oidc: token_endpoint returned HTTP error status %(status_code)s for %(issuer)s with'
' content %(content)s'
% {
'issuer': provider.issuer,
'status_code': status_code,
@ -220,7 +220,8 @@ class LoginCallback(View):
messages.warning(
request,
_(
'Authentication on %(name)s failed with error "%(error)s", report %(request_id)s to an administrator. '
'Authentication on %(name)s failed with error "%(error)s", report %(request_id)s to'
' an administrator. '
)
% {
'name': provider.name,
@ -231,7 +232,7 @@ class LoginCallback(View):
else:
messages.warning(
request,
_('Provider %(name)s is down, report %(request_id)s to ' 'an administrator. ')
_('Provider %(name)s is down, report %(request_id)s to an administrator. ')
% {
'name': provider.name,
'request_id': request.request_id,
@ -249,7 +250,7 @@ class LoginCallback(View):
)
messages.warning(
request,
_('Provider %(name)s is down, report %(request_id)s to ' 'an administrator. ')
_('Provider %(name)s is down, report %(request_id)s to an administrator. ')
% {
'name': provider.name,
'request_id': request.request_id,
@ -265,7 +266,7 @@ class LoginCallback(View):
)
messages.warning(
request,
_('Provider %(name)s is down, report %(request_id)s to ' 'an administrator. ')
_('Provider %(name)s is down, report %(request_id)s to an administrator. ')
% {
'name': provider.name,
'request_id': request.request_id,
@ -284,7 +285,7 @@ class LoginCallback(View):
)
messages.warning(
request,
_('Provider %(name)s is down, report %(request_id)s to ' 'an administrator. ')
_('Provider %(name)s is down, report %(request_id)s to an administrator. ')
% {
'name': provider.name,
'request_id': request.request_id,
@ -324,7 +325,7 @@ class LoginCallback(View):
if provider:
messages.warning(
request,
_('Login with %(name)s failed, report %(request_id)s ' 'to an administrator.')
_('Login with %(name)s failed, report %(request_id)s to an administrator.')
% {
'name': provider.name,
'request_id': request.request_id,
@ -333,7 +334,7 @@ class LoginCallback(View):
else:
messages.warning(
request,
_('Login with OpenIDConnect failed, report %s to an ' 'administrator') % request.request_id,
_('Login with OpenIDConnect failed, report %s to an administrator') % request.request_id,
)
return self.continue_to_next_url(request)

View File

@ -37,7 +37,10 @@ class Migration(migrations.Migration):
(
'logout_url',
models.URLField(
help_text='you can use a {} to pass the URL of the success icon, ex.: http://example.com/logout?next={}',
help_text=(
'you can use a {} to pass the URL of the success icon, ex.:'
' http://example.com/logout?next={}'
),
max_length=255,
null=True,
verbose_name='url',
@ -54,7 +57,10 @@ class Migration(migrations.Migration):
'logout_use_iframe_timeout',
models.PositiveIntegerField(
default=300,
help_text="if iframe logout is used, it's the time between the onload event for this iframe and the moment we consider its loading to be really finished",
help_text=(
"if iframe logout is used, it's the time between the onload event for this iframe"
" and the moment we consider its loading to be really finished"
),
verbose_name='iframe logout timeout (ms)',
),
),

View File

@ -159,9 +159,8 @@ class OIDCClient(Service):
except ValueError:
raise ValidationError(
_(
'Redirect URIs must have the same domain or you must define a '
'sector identifier URI if you want to use pairwise'
'identifiers'
'Redirect URIs must have the same domain or you must define a sector identifier URI'
' if you want to use pairwiseidentifiers'
)
)
@ -220,9 +219,7 @@ class OIDCClient(Service):
raise ValueError('all redirect_uri do not have the same hostname')
elif self.authorization_mode == self.AUTHORIZATION_MODE_BY_OU:
if not self.ou:
raise ValidationError(
_('OU-based authorization requires that the client be ' 'within an OU.')
)
raise ValidationError(_('OU-based authorization requires that the client be within an OU.'))
sector_identifier = self.ou.slug
else:
raise NotImplementedError('unknown self.authorization_mode %s' % self.authorization_mode)

View File

@ -288,8 +288,8 @@ def authorize_for_client(request, client, redirect_uri):
if client.authorization_flow == client.FLOW_RESOURCE_OWNER_CRED:
raise InvalidRequest(
_(
'Client is configured for resource owner password credentials grant, '
'authorize endpoint is not usable'
'Client is configured for resource owner password credentials grant, authorize endpoint is'
' not usable'
)
)
if client.authorization_flow == client.FLOW_AUTHORIZATION_CODE:
@ -590,7 +590,7 @@ def idtoken_from_user_credential(request):
if request.META.get('CONTENT_TYPE') != 'application/x-www-form-urlencoded':
raise InvalidRequest(
_('Wrong content type. request content type must be ' '\'application/x-www-form-urlencoded\''),
_('Wrong content type. request content type must be \'application/x-www-form-urlencoded\''),
client=client,
)
username = request.POST.get('username')
@ -602,16 +602,15 @@ def idtoken_from_user_credential(request):
if not all((username, request.POST.get('password'))):
raise InvalidRequest(
_(
'Request must bear both username and password as '
'parameters using the "application/x-www-form-urlencoded" '
'media type'
'Request must bear both username and password as parameters using the'
' "application/x-www-form-urlencoded" media type'
),
client=client,
)
if client.authorization_flow != models.OIDCClient.FLOW_RESOURCE_OWNER_CRED:
raise UnauthorizedClient(
_('Client is not configured for resource owner password ' 'credential grant'), client=client
_('Client is not configured for resource owner password credential grant'), client=client
)
exponential_backoff = ExponentialRetryTimeout(
@ -626,7 +625,7 @@ def idtoken_from_user_credential(request):
seconds_to_wait = a2_app_settings.A2_LOGIN_EXPONENTIAL_RETRY_TIMEOUT_MAX_DURATION
if seconds_to_wait:
raise InvalidRequest(
_('Too many attempts with erroneous RO password, you must wait ' '%s seconds to try again.')
_('Too many attempts with erroneous RO password, you must wait %s seconds to try again.')
% int(math.ceil(seconds_to_wait)),
client=client,
)

View File

@ -283,16 +283,15 @@ class PermissionMixin(models.Model):
is_superuser = models.BooleanField(
_('superuser status'),
default=False,
help_text=_('Designates that this user has all permissions ' 'without explicitly assigning them.'),
help_text=_('Designates that this user has all permissions without explicitly assigning them.'),
)
groups = models.ManyToManyField(
to=Group,
verbose_name=_('groups'),
blank=True,
help_text=_(
'The groups this user belongs to. A user will get '
'all permissions granted to each of his/her '
'group.'
'The groups this user belongs to. A user will get all permissions granted to each of his/her'
' group.'
),
related_name="user_set",
related_query_name="user",

View File

@ -512,7 +512,7 @@ def migration(request, transactional_db):
return executor._create_project_state(with_applied_migrations=True).apps
def apply(self, targets):
""" Migrate forwards to the "targets" migration """
"""Migrate forwards to the "targets" migration"""
executor = MigrationExecutor(connection)
executor.migrate(targets)
executor.loader.build_graph()

View File

@ -79,11 +79,7 @@ payload_decoded = {
header_rsa = 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ'
header_ec = 'eyJhbGciOiJFUzI1NiIsImtpZCI6ImpiMjBDZzgifQ'
header_hmac = 'eyJhbGciOiJIUzI1NiJ9'
payload = (
'eyJhdWQiOiJzNkJoZFJrcXQzIiwiZXhwIjoyMjAxMDk0Mjc4LCJpYXQiOjEzMTEyOD'
'A5NzAsImlzcyI6Imh0dHA6Ly9zZXJ2ZXIuZXhhbXBsZS5jb20iLCJub25jZSI6Im4t'
'MFM2X1d6QTJNaiIsInN1YiI6IjI0ODI4OTc2MTAwMSJ9'
)
payload = 'eyJhdWQiOiJzNkJoZFJrcXQzIiwiZXhwIjoyMjAxMDk0Mjc4LCJpYXQiOjEzMTEyODA5NzAsImlzcyI6Imh0dHA6Ly9zZXJ2ZXIuZXhhbXBsZS5jb20iLCJub25jZSI6Im4tMFM2X1d6QTJNaiIsInN1YiI6IjI0ODI4OTc2MTAwMSJ9'
def test_parse_id_token(code, oidc_provider, oidc_provider_jwkset):

View File

@ -306,12 +306,13 @@ def test_check_and_repair_managers_of_roles(db, capsys):
assert 'Managers of Role 1" wrong ou, should be "Default organizational unit"' in captured.out
assert 'invalid permission "Management / role / Role 1": not manage_members operation' in captured.out
assert (
'invalid permission "Management / role / Role 1": ' 'not admin_scope and not self manage permission'
) in captured.out
'invalid permission "Management / role / Role 1": not admin_scope and not self manage permission'
in captured.out
)
assert (
'invalid admin role "Managers of Role 1" '
'wrong ou, should be "Default organizational unit" is "None"'
) in captured.out
'invalid admin role "Managers of Role 1" wrong ou, should be "Default organizational unit" is "None"'
in captured.out
)
perm1.refresh_from_db()
assert perm1.ou is None

View File

@ -23,7 +23,7 @@ def test_sha256_hasher():
hasher = hashers.SHA256PasswordHasher()
hashed = hasher.encode('admin', '')
assert hasher.verify('admin', hashed)
assert hashed == 'sha256$$8c6976e5b5410415b' 'de908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918'
assert hashed == 'sha256$$8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918'
def test_openldap_hashers():

View File

@ -86,17 +86,7 @@ class CasTests(Authentic2TestCase):
self.factory = RequestFactory()
def test_long_urls(self):
self.service.urls = (
'https://casclient.com/%C3%A9/'
'lorem/ipsum/dolor/sit/amet/consectetur/adipiscing/elit/sed/do/'
'eiusmod/tempor/incididunt/ut/labore/et/dolore/magna/aliqua/ut/'
'enim/ad/minim/veniam/quis/nostrud/exercitation/ullamco/laboris/'
'nisi/ut/aliquip/ex/ea/commodo/consequat/duis/aute/irure/dolor/'
'in/reprehenderit/in/voluptate/velit/esse/cillum/dolore/eu/'
'fugiat/nulla/pariatur/excepteur/sint/occaecat/cupidatat/non/'
'proident/sunt/in/culpa/qui/officia/deserunt/mollit/anim/id/est/'
'laborum'
)
self.service.urls = 'https://casclient.com/%C3%A9/lorem/ipsum/dolor/sit/amet/consectetur/adipiscing/elit/sed/do/eiusmod/tempor/incididunt/ut/labore/et/dolore/magna/aliqua/ut/enim/ad/minim/veniam/quis/nostrud/exercitation/ullamco/laboris/nisi/ut/aliquip/ex/ea/commodo/consequat/duis/aute/irure/dolor/in/reprehenderit/in/voluptate/velit/esse/cillum/dolore/eu/fugiat/nulla/pariatur/excepteur/sint/occaecat/cupidatat/non/proident/sunt/in/culpa/qui/officia/deserunt/mollit/anim/id/est/laborum'
self.service.save()
def test_service_matching(self):

View File

@ -434,101 +434,90 @@ class Scenario:
)
constraints += (
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='first-name']/" "@NameFormat",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='first-name']/@NameFormat",
lasso.SAML2_ATTRIBUTE_NAME_FORMAT_BASIC,
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='first-name']/" "@FriendlyName",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='first-name']/@FriendlyName",
'First name',
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='first-name']/"
"saml:AttributeValue",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='first-name']/saml:AttributeValue",
'John',
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='last-name']/" "@NameFormat",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='last-name']/@NameFormat",
lasso.SAML2_ATTRIBUTE_NAME_FORMAT_BASIC,
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='last-name']/" "@FriendlyName",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='last-name']/@FriendlyName",
'Last name',
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='last-name']/"
"saml:AttributeValue",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='last-name']/saml:AttributeValue",
'Doe',
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='code_code']/" "@NameFormat",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='code_code']/@NameFormat",
lasso.SAML2_ATTRIBUTE_NAME_FORMAT_BASIC,
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='code_code']/" "@FriendlyName",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='code_code']/@FriendlyName",
'code',
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='code_code']/"
"saml:AttributeValue",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='code_code']/saml:AttributeValue",
'1234',
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='mobile']/" "@NameFormat",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='mobile']/@NameFormat",
lasso.SAML2_ATTRIBUTE_NAME_FORMAT_BASIC,
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='mobile']/" "@FriendlyName",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='mobile']/@FriendlyName",
'mobile',
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='mobile']/"
"saml:AttributeValue",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='mobile']/saml:AttributeValue",
'5678',
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='avatar']/" "@NameFormat",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='avatar']/@NameFormat",
lasso.SAML2_ATTRIBUTE_NAME_FORMAT_BASIC,
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='avatar']/" "@FriendlyName",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='avatar']/@FriendlyName",
'Avatar',
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='avatar']/"
"saml:AttributeValue",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='avatar']/saml:AttributeValue",
re.compile('^http://testserver/media/profile-image/.*$'),
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='verified_attributes']/"
"@NameFormat",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='verified_attributes']/@NameFormat",
lasso.SAML2_ATTRIBUTE_NAME_FORMAT_BASIC,
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='verified_attributes']/"
"@FriendlyName",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='verified_attributes']/@FriendlyName",
'Verified attributes',
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='verified_attributes']/"
"saml:AttributeValue",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='verified_attributes']/saml:AttributeValue",
{'code_code', 'mobile'},
),
)
if user is not None and self.sp.admin_role in user.roles.all():
constraints += (
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='superuser']/"
"@NameFormat",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='superuser']/@NameFormat",
lasso.SAML2_ATTRIBUTE_NAME_FORMAT_BASIC,
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='superuser']/"
"@FriendlyName",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='superuser']/@FriendlyName",
'Superuser status',
),
(
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='superuser']/"
"saml:AttributeValue",
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='superuser']/saml:AttributeValue",
'true',
),
)
@ -772,8 +761,9 @@ def test_make_edu_person_targeted_id(db, settings, rf):
settings.A2_IDP_SAML2_EDU_PERSON_TARGETED_ID_SALT = 'b'
settings.A2_IDP_SAML2_EDU_PERSON_TARGETED_ID_ATTRIBUTE = 'username'
assert saml2_endpoints.make_edu_person_targeted_id_value(provider, user) == (
'_A485C0ACEEF43A6D39145F5CFE25D9D3B6F15DC6443F412263C76D81C72DA8D5'
assert (
saml2_endpoints.make_edu_person_targeted_id_value(provider, user)
== '_A485C0ACEEF43A6D39145F5CFE25D9D3B6F15DC6443F412263C76D81C72DA8D5'
)
assert (
@ -785,7 +775,7 @@ def test_make_edu_person_targeted_id(db, settings, rf):
assert edpt is not None
node = lasso.Node.newFromXmlNode(force_str(ET.tostring(edpt)))
assert isinstance(node, lasso.Saml2NameID)
assert force_text(node.content) == ('_A485C0ACEEF43A6D39145F5CFE25D9D3B6F15DC6443F412263C76D81C72DA8D5')
assert force_text(node.content) == '_A485C0ACEEF43A6D39145F5CFE25D9D3B6F15DC6443F412263C76D81C72DA8D5'
assert node.format == lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT
assert node.nameQualifier == 'http://testserver/idp/saml2/metadata'
@ -818,7 +808,7 @@ def test_add_attributes_edu_person_targeted_id_nid_format(db, settings, rf, add_
assert len(attributes[edu_name]) == 1
node = lasso.Node.newFromXmlNode(force_str(list(attributes[edu_name])[0]))
assert isinstance(node, lasso.Saml2NameID)
assert force_text(node.content) == ('_A485C0ACEEF43A6D39145F5CFE25D9D3B6F15DC6443F412263C76D81C72DA8D5')
assert force_text(node.content) == '_A485C0ACEEF43A6D39145F5CFE25D9D3B6F15DC6443F412263C76D81C72DA8D5'
assert node.format == lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT
assert node.nameQualifier == 'http://testserver/idp/saml2/metadata'
assert node.spNameQualifier == 'https://sp.com/'
@ -850,7 +840,7 @@ def test_add_attributes_edu_person_targeted_id_attribute(db, settings, rf, add_a
assert len(attributes['edupersontargetedid']) == 1
node = lasso.Node.newFromXmlNode(force_str(list(attributes['edupersontargetedid'])[0]))
assert isinstance(node, lasso.Saml2NameID)
assert force_text(node.content) == ('_A485C0ACEEF43A6D39145F5CFE25D9D3B6F15DC6443F412263C76D81C72DA8D5')
assert force_text(node.content) == '_A485C0ACEEF43A6D39145F5CFE25D9D3B6F15DC6443F412263C76D81C72DA8D5'
assert node.format == lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT
assert node.nameQualifier == 'http://testserver/idp/saml2/metadata'
assert node.spNameQualifier == 'https://sp.com/'

View File

@ -474,7 +474,7 @@ def test_global_journal(app, superuser, events):
'user': 'agent',
},
{
'message': 'deletion of authorization of single sign on with "service" of ' 'user "Johnny doe"',
'message': 'deletion of authorization of single sign on with "service" of user "Johnny doe"',
'timestamp': 'Jan. 2, 2020, 3 a.m.',
'type': 'manager.user.sso.authorization.deletion',
'user': 'agent',
@ -510,13 +510,13 @@ def test_global_journal(app, superuser, events):
'user': 'agent',
},
{
'message': 'inheritance addition from parent role "role2" to child role ' '"role1"',
'message': 'inheritance addition from parent role "role2" to child role "role1"',
'timestamp': 'Jan. 2, 2020, 9 a.m.',
'type': 'manager.role.inheritance.addition',
'user': 'agent',
},
{
'message': 'inheritance removal from parent role "role2" to child role ' '"role1"',
'message': 'inheritance removal from parent role "role2" to child role "role1"',
'timestamp': 'Jan. 2, 2020, 10 a.m.',
'type': 'manager.role.inheritance.removal',
'user': 'agent',
@ -534,7 +534,7 @@ def test_global_journal(app, superuser, events):
'user': 'agent',
},
{
'message': 'addition of user "user (111111)" as administrator of role ' '"role1"',
'message': 'addition of user "user (111111)" as administrator of role "role1"',
'timestamp': 'Jan. 2, 2020, 1 p.m.',
'type': 'manager.role.administrator.user.addition',
'user': 'agent',
@ -561,16 +561,24 @@ def test_global_journal(app, superuser, events):
'timestamp': 'Jan. 2, 2020, 5 p.m.',
'type': 'manager.user.deactivation',
'user': '-',
'message': 'automatic deactivation of user "Johnny doe" because the associated LDAP account does not exist anymore',
'message': (
'automatic deactivation of user "Johnny doe" because the associated LDAP account does not'
' exist anymore'
),
},
{
'timestamp': 'Jan. 2, 2020, 6 p.m.',
'type': 'manager.user.deactivation',
'user': '-',
'message': 'automatic deactivation of user "Johnny doe" because the associated LDAP source has been deleted',
'message': (
'automatic deactivation of user "Johnny doe" because the associated LDAP source has been'
' deleted'
),
},
{
'message': 'automatic activation of user "Johnny doe" because the associated LDAP account reappeared',
'message': (
'automatic activation of user "Johnny doe" because the associated LDAP account reappeared'
),
'timestamp': 'Jan. 2, 2020, 7 p.m.',
'type': 'manager.user.activation',
'user': '-',
@ -683,7 +691,7 @@ def test_user_journal(app, superuser, events):
'user': 'agent',
},
{
'message': "password reset request by administrator sent to " '"user@example.com"',
'message': "password reset request by administrator sent to \"user@example.com\"",
'timestamp': 'Jan. 1, 2020, 9 p.m.',
'type': 'manager.user.password.reset.request',
'user': 'agent',
@ -719,7 +727,7 @@ def test_user_journal(app, superuser, events):
'user': 'agent',
},
{
'message': 'deletion of authorization of single sign on with "service" by ' "administrator",
'message': 'deletion of authorization of single sign on with "service" by administrator',
'timestamp': 'Jan. 2, 2020, 3 a.m.',
'type': 'manager.user.sso.authorization.deletion',
'user': 'agent',
@ -928,13 +936,13 @@ def test_roles_journal(app, superuser, events):
'user': 'agent',
},
{
'message': 'inheritance addition from parent role "role2" to child role ' '"role1"',
'message': 'inheritance addition from parent role "role2" to child role "role1"',
'timestamp': 'Jan. 2, 2020, 9 a.m.',
'type': 'manager.role.inheritance.addition',
'user': 'agent',
},
{
'message': 'inheritance removal from parent role "role2" to child role ' '"role1"',
'message': 'inheritance removal from parent role "role2" to child role "role1"',
'timestamp': 'Jan. 2, 2020, 10 a.m.',
'type': 'manager.role.inheritance.removal',
'user': 'agent',
@ -952,7 +960,7 @@ def test_roles_journal(app, superuser, events):
'user': 'agent',
},
{
'message': 'addition of user "user (111111)" as administrator of role ' '"role1"',
'message': 'addition of user "user (111111)" as administrator of role "role1"',
'timestamp': 'Jan. 2, 2020, 1 p.m.',
'type': 'manager.role.administrator.user.addition',
'user': 'agent',
@ -1047,7 +1055,8 @@ def test_search(app, superuser, events):
assert table_content == [
'automatic activation of user "Johnny doe" because the associated LDAP account reappeared',
'automatic deactivation of user "Johnny doe" because the associated LDAP source has been deleted',
'automatic deactivation of user "Johnny doe" because the associated LDAP account does not exist anymore',
'automatic deactivation of user "Johnny doe" because the associated LDAP account does not exist'
' anymore',
'deactivation of user "Johnny doe"',
'activation of user "Johnny doe"',
'mandatory password change at next login unset for user "Johnny doe"',