mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-30 20:55:42 +00:00 
			
		
		
		
	[FR] Enable restrictions on allowed domains for signup (#4172)
* [FR] Enable restrictions on allowed domains for signup Fixes #4168 * raise permission errors * add setting to page * move checks to clean_email * remove unneeded check * simplify * log error to database * factor settings fnc call out * Add validation before setting save * add before_save to accepted tokens
This commit is contained in:
		| @@ -215,9 +215,35 @@ class RegistratonMixin: | ||||
|             return super().is_open_for_signup(request, *args, **kwargs) | ||||
|         return False | ||||
|  | ||||
|     def clean_email(self, email): | ||||
|         """Check if the mail is valid to the pattern in LOGIN_SIGNUP_MAIL_RESTRICTION (if enabled in settings).""" | ||||
|         mail_restriction = InvenTreeSetting.get_setting('LOGIN_SIGNUP_MAIL_RESTRICTION', None) | ||||
|         if not mail_restriction: | ||||
|             return super().clean_email(email) | ||||
|  | ||||
|         split_email = email.split('@') | ||||
|         if len(split_email) != 2: | ||||
|             logger.error(f'The user {email} has an invalid email address') | ||||
|             raise forms.ValidationError(_('The provided primary email address is not valid.')) | ||||
|  | ||||
|         mailoptions = mail_restriction.split(',') | ||||
|         for option in mailoptions: | ||||
|             if not option.startswith('@'): | ||||
|                 log_error('LOGIN_SIGNUP_MAIL_RESTRICTION is not configured correctly') | ||||
|                 raise forms.ValidationError(_('The provided primary email address is not valid.')) | ||||
|             else: | ||||
|                 if split_email[1] == option[1:]: | ||||
|                     return super().clean_email(email) | ||||
|  | ||||
|         logger.info(f'The provided email domain for {email} is not approved') | ||||
|         raise forms.ValidationError(_('The provided email domain is not approved.')) | ||||
|  | ||||
|     def save_user(self, request, user, form, commit=True): | ||||
|         """Check if a default group is set in settings.""" | ||||
|         # Create the user | ||||
|         user = super().save_user(request, user, form) | ||||
|  | ||||
|         # Check if a default group is set in settings | ||||
|         start_group = InvenTreeSetting.get_setting('SIGNUP_GROUP') | ||||
|         if start_group: | ||||
|             try: | ||||
|   | ||||
| @@ -11,6 +11,7 @@ import json | ||||
| import logging | ||||
| import math | ||||
| import os | ||||
| import re | ||||
| import uuid | ||||
| from datetime import datetime, timedelta | ||||
| from enum import Enum | ||||
| @@ -81,19 +82,33 @@ class BaseInvenTreeSetting(models.Model): | ||||
|         self.clean(**kwargs) | ||||
|         self.validate_unique(**kwargs) | ||||
|  | ||||
|         # Execute before_save action | ||||
|         self._call_settings_function('before_save', args, kwargs) | ||||
|  | ||||
|         # Update this setting in the cache | ||||
|         if do_cache: | ||||
|             self.save_to_cache() | ||||
|  | ||||
|         super().save() | ||||
|  | ||||
|         # Get after_save action | ||||
|         # Execute after_save action | ||||
|         self._call_settings_function('after_save', args, kwargs) | ||||
|  | ||||
|     def _call_settings_function(self, reference: str, args, kwargs): | ||||
|         """Call a function associated with a particular setting. | ||||
|  | ||||
|         Args: | ||||
|             reference (str): The name of the function to call | ||||
|             args: Positional arguments to pass to the function | ||||
|             kwargs: Keyword arguments to pass to the function | ||||
|         """ | ||||
|         # Get action | ||||
|         setting = self.get_setting_definition(self.key, *args, **kwargs) | ||||
|         after_save = setting.get('after_save', None) | ||||
|         settings_fnc = setting.get(reference, None) | ||||
|  | ||||
|         # Execute if callable | ||||
|         if callable(after_save): | ||||
|             after_save(self) | ||||
|         if callable(settings_fnc): | ||||
|             settings_fnc(self) | ||||
|  | ||||
|     @property | ||||
|     def cache_key(self): | ||||
| @@ -771,6 +786,19 @@ def update_instance_name(setting): | ||||
|     site_obj.save() | ||||
|  | ||||
|  | ||||
| def validate_email_domains(setting): | ||||
|     """Validate the email domains setting.""" | ||||
|     if not setting.value: | ||||
|         return | ||||
|  | ||||
|     domains = setting.value.split(',') | ||||
|     for domain in domains: | ||||
|         if not domain: | ||||
|             raise ValidationError(_('An empty domain is not allowed.')) | ||||
|         if not re.match(r'^@[a-zA-Z0-9\.\-_]+$', domain): | ||||
|             raise ValidationError(_(f'Invalid domain name: {domain}')) | ||||
|  | ||||
|  | ||||
| class InvenTreeSetting(BaseInvenTreeSetting): | ||||
|     """An InvenTreeSetting object is a key:value pair used for storing single values (e.g. one-off settings values). | ||||
|  | ||||
| @@ -1375,6 +1403,13 @@ class InvenTreeSetting(BaseInvenTreeSetting): | ||||
|             'validator': bool, | ||||
|         }, | ||||
|  | ||||
|         'LOGIN_SIGNUP_MAIL_RESTRICTION': { | ||||
|             'name': _('Allowed domains'), | ||||
|             'description': _('Restrict signup to certain domains (comma-separated, strarting with @)'), | ||||
|             'default': '', | ||||
|             'before_save': validate_email_domains, | ||||
|         }, | ||||
|  | ||||
|         'SIGNUP_GROUP': { | ||||
|             'name': _('Group on signup'), | ||||
|             'description': _('Group to which new users are assigned on registration'), | ||||
|   | ||||
| @@ -134,6 +134,7 @@ class SettingsTest(InvenTreeTestCase): | ||||
|             'units', | ||||
|             'requires_restart', | ||||
|             'after_save', | ||||
|             'before_save', | ||||
|         ] | ||||
|  | ||||
|         for k in setting.keys(): | ||||
|   | ||||
| @@ -30,6 +30,7 @@ | ||||
|         {% include "InvenTree/settings/setting.html" with key="LOGIN_SIGNUP_MAIL_TWICE" icon="fa-at" %} | ||||
|         {% include "InvenTree/settings/setting.html" with key="LOGIN_SIGNUP_PWD_TWICE" icon="fa-user-lock" %} | ||||
|         {% include "InvenTree/settings/setting.html" with key="SIGNUP_GROUP" icon="fa-users" %} | ||||
|         {% include "InvenTree/settings/setting.html" with key="LOGIN_SIGNUP_MAIL_RESTRICTION" icon="fa-sitemap" %} | ||||
|         <tr> | ||||
|             <th><h5>{% trans 'Single Sign On' %}</h5></th> | ||||
|             <td colspan='4'></td> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user