Compare commits
	
		
			5 Commits
		
	
	
		
			version/0.
			...
			version/0.
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b4cb157257 | |||
| d9ccbdd962 | |||
| d5ab20ee12 | |||
| 0e73702fca | |||
| 58ebd15ada | 
| @ -1,5 +1,5 @@ | |||||||
| [bumpversion] | [bumpversion] | ||||||
| current_version = 0.0.3-alpha | current_version = 0.0.4-alpha | ||||||
| tag = True | tag = True | ||||||
| commit = True | commit = True | ||||||
| parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*) | parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*) | ||||||
| @ -20,6 +20,8 @@ values = | |||||||
|  |  | ||||||
| [bumpversion:file:passbook/__init__.py] | [bumpversion:file:passbook/__init__.py] | ||||||
|  |  | ||||||
|  | [bumpversion:file:passbook/api/__init__.py] | ||||||
|  |  | ||||||
| [bumpversion:file:passbook/core/__init__.py] | [bumpversion:file:passbook/core/__init__.py] | ||||||
|  |  | ||||||
| [bumpversion:file:passbook/admin/__init__.py] | [bumpversion:file:passbook/admin/__init__.py] | ||||||
| @ -30,6 +32,8 @@ values = | |||||||
|  |  | ||||||
| [bumpversion:file:passbook/ldap/__init__.py] | [bumpversion:file:passbook/ldap/__init__.py] | ||||||
|  |  | ||||||
|  | [bumpversion:file:passbook/lib/__init__.py] | ||||||
|  |  | ||||||
| [bumpversion:file:passbook/saml_idp/__init__.py] | [bumpversion:file:passbook/saml_idp/__init__.py] | ||||||
|  |  | ||||||
| [bumpversion:file:passbook/audit/__init__.py] | [bumpversion:file:passbook/audit/__init__.py] | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ package-docker: | |||||||
|   before_script: |   before_script: | ||||||
|     - echo "{\"auths\":{\"https://docker.$NEXUS_URL/\":{\"username\":\"$NEXUS_USER\",\"password\":\"$NEXUS_PASS\"}}}" > /kaniko/.docker/config.json |     - echo "{\"auths\":{\"https://docker.$NEXUS_URL/\":{\"username\":\"$NEXUS_USER\",\"password\":\"$NEXUS_PASS\"}}}" > /kaniko/.docker/config.json | ||||||
|   script: |   script: | ||||||
|     - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination docker.pkg.beryju.org/passbook:latest --destination docker.pkg.beryju.org/passbook:0.0.3-alpha |     - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination docker.pkg.beryju.org/passbook:latest --destination docker.pkg.beryju.org/passbook:0.0.4-alpha | ||||||
|   stage: build |   stage: build | ||||||
|   only: |   only: | ||||||
|     - tags |     - tags | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| apiVersion: v1 | apiVersion: v1 | ||||||
| appVersion: "0.0.3-alpha" | appVersion: "0.0.4-alpha" | ||||||
| description: A Helm chart for passbook. | description: A Helm chart for passbook. | ||||||
| name: passbook | name: passbook | ||||||
| version: 1.0.0 | version: 1.0.0 | ||||||
|  | |||||||
| @ -1,2 +1,2 @@ | |||||||
| """passbook""" | """passbook""" | ||||||
| __version__ = '0.0.3-alpha' | __version__ = '0.0.4-alpha' | ||||||
|  | |||||||
| @ -1,2 +1,2 @@ | |||||||
| """passbook admin""" | """passbook admin""" | ||||||
| __version__ = '0.0.3-alpha' | __version__ = '0.0.4-alpha' | ||||||
|  | |||||||
| @ -8,3 +8,4 @@ class PassbookAdminConfig(AppConfig): | |||||||
|     name = 'passbook.admin' |     name = 'passbook.admin' | ||||||
|     label = 'passbook_admin' |     label = 'passbook_admin' | ||||||
|     mountpoint = 'administration/' |     mountpoint = 'administration/' | ||||||
|  |     verbose_name = 'passbook Admin' | ||||||
|  | |||||||
| @ -1,2 +1,2 @@ | |||||||
| """passbook api""" | """passbook api""" | ||||||
| __version__ = '0.0.1-alpha' | __version__ = '0.0.4-alpha' | ||||||
|  | |||||||
| @ -9,3 +9,4 @@ class PassbookAPIConfig(AppConfig): | |||||||
|     name = 'passbook.api' |     name = 'passbook.api' | ||||||
|     label = 'passbook_api' |     label = 'passbook_api' | ||||||
|     mountpoint = 'api/' |     mountpoint = 'api/' | ||||||
|  |     verbose_name = 'passbook API' | ||||||
|  | |||||||
							
								
								
									
										3
									
								
								passbook/api/requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								passbook/api/requirements.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | django-rest-framework | ||||||
|  | drf_yasg | ||||||
|  | django-filters | ||||||
| @ -1,2 +1,2 @@ | |||||||
| """passbook audit Header""" | """passbook audit Header""" | ||||||
| __version__ = '0.0.3-alpha' | __version__ = '0.0.4-alpha' | ||||||
|  | |||||||
| @ -1,2 +1,2 @@ | |||||||
| """passbook captcha_factor Header""" | """passbook captcha_factor Header""" | ||||||
| __version__ = '0.0.3-alpha' | __version__ = '0.0.4-alpha' | ||||||
|  | |||||||
| @ -1,2 +1,2 @@ | |||||||
| """passbook core""" | """passbook core""" | ||||||
| __version__ = '0.0.3-alpha' | __version__ = '0.0.4-alpha' | ||||||
|  | |||||||
							
								
								
									
										35
									
								
								passbook/core/migrations/0002_auto_20190208_1514.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								passbook/core/migrations/0002_auto_20190208_1514.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | |||||||
|  | # Generated by Django 2.1.5 on 2019-02-08 15:14 | ||||||
|  |  | ||||||
|  | import django.db.models.deletion | ||||||
|  | from django.db import migrations, models | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  |  | ||||||
|  |     dependencies = [ | ||||||
|  |         ('passbook_core', '0001_initial'), | ||||||
|  |     ] | ||||||
|  |  | ||||||
|  |     operations = [ | ||||||
|  |         migrations.CreateModel( | ||||||
|  |             name='PasswordPolicyRule', | ||||||
|  |             fields=[ | ||||||
|  |                 ('rule_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='passbook_core.Rule')), | ||||||
|  |                 ('amount_uppercase', models.IntegerField(default=0)), | ||||||
|  |                 ('amount_lowercase', models.IntegerField(default=0)), | ||||||
|  |                 ('amount_symbols', models.IntegerField(default=0)), | ||||||
|  |                 ('length_min', models.IntegerField(default=0)), | ||||||
|  |                 ('symbol_charset', models.TextField(default='!\\"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ ')), | ||||||
|  |             ], | ||||||
|  |             options={ | ||||||
|  |                 'verbose_name': 'Password Policy Rule', | ||||||
|  |                 'verbose_name_plural': 'Password Policy Rules', | ||||||
|  |             }, | ||||||
|  |             bases=('passbook_core.rule',), | ||||||
|  |         ), | ||||||
|  |         migrations.AlterField( | ||||||
|  |             model_name='fieldmatcherrule', | ||||||
|  |             name='user_field', | ||||||
|  |             field=models.TextField(choices=[('username', 'Username'), ('first_name', 'First Name'), ('last_name', 'Last Name'), ('email', 'E-Mail'), ('is_staff', 'Is staff'), ('is_active', 'Is active'), ('data_joined', 'Date joined')]), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
| @ -82,7 +82,7 @@ class Application(RuleModel): | |||||||
|     def user_is_authorized(self, user: User) -> bool: |     def user_is_authorized(self, user: User) -> bool: | ||||||
|         """Check if user is authorized to use this application""" |         """Check if user is authorized to use this application""" | ||||||
|         from passbook.core.rules import RuleEngine |         from passbook.core.rules import RuleEngine | ||||||
|         return RuleEngine(self).for_user(user).result |         return RuleEngine(self.rules.all()).for_user(user).result | ||||||
|  |  | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return self.name |         return self.name | ||||||
| @ -160,6 +160,7 @@ class FieldMatcherRule(Rule): | |||||||
|     MATCH_CONTAINS = 'contains' |     MATCH_CONTAINS = 'contains' | ||||||
|     MATCH_REGEXP = 'regexp' |     MATCH_REGEXP = 'regexp' | ||||||
|     MATCH_EXACT = 'exact' |     MATCH_EXACT = 'exact' | ||||||
|  |  | ||||||
|     MATCHES = ( |     MATCHES = ( | ||||||
|         (MATCH_STARTSWITH, _('Starts with')), |         (MATCH_STARTSWITH, _('Starts with')), | ||||||
|         (MATCH_ENDSWITH, _('Ends with')), |         (MATCH_ENDSWITH, _('Ends with')), | ||||||
| @ -169,13 +170,13 @@ class FieldMatcherRule(Rule): | |||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     USER_FIELDS = ( |     USER_FIELDS = ( | ||||||
|         ('username', 'username',), |         ('username', _('Username'),), | ||||||
|         ('first_name', 'first_name',), |         ('first_name', _('First Name'),), | ||||||
|         ('last_name', 'last_name',), |         ('last_name', _('Last Name'),), | ||||||
|         ('email', 'email',), |         ('email', _('E-Mail'),), | ||||||
|         ('is_staff', 'is_staff',), |         ('is_staff', _('Is staff'),), | ||||||
|         ('is_active', 'is_active',), |         ('is_active', _('Is active'),), | ||||||
|         ('data_joined', 'data_joined',), |         ('data_joined', _('Date joined'),), | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     user_field = models.TextField(choices=USER_FIELDS) |     user_field = models.TextField(choices=USER_FIELDS) | ||||||
| @ -218,6 +219,41 @@ class FieldMatcherRule(Rule): | |||||||
|         verbose_name = _('Field matcher Rule') |         verbose_name = _('Field matcher Rule') | ||||||
|         verbose_name_plural = _('Field matcher Rules') |         verbose_name_plural = _('Field matcher Rules') | ||||||
|  |  | ||||||
|  | @reversion.register() | ||||||
|  | class PasswordPolicyRule(Rule): | ||||||
|  |     """Rule to make sure passwords have certain properties""" | ||||||
|  |  | ||||||
|  |     amount_uppercase = models.IntegerField(default=0) | ||||||
|  |     amount_lowercase = models.IntegerField(default=0) | ||||||
|  |     amount_symbols = models.IntegerField(default=0) | ||||||
|  |     length_min = models.IntegerField(default=0) | ||||||
|  |     symbol_charset = models.TextField(default=r"!\"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ ") | ||||||
|  |  | ||||||
|  |     form = 'passbook.core.forms.rules.PasswordPolicyRuleForm' | ||||||
|  |  | ||||||
|  |     def passes(self, user: User) -> bool: | ||||||
|  |         # Only check if password is being set | ||||||
|  |         if not hasattr(user, '__password__'): | ||||||
|  |             return True | ||||||
|  |         password = getattr(user, '__password__') | ||||||
|  |  | ||||||
|  |         filter_regex = r'' | ||||||
|  |         if self.amount_lowercase > 0: | ||||||
|  |             filter_regex += r'[a-z]{%d,}' % self.amount_lowercase | ||||||
|  |         if self.amount_uppercase > 0: | ||||||
|  |             filter_regex += r'[A-Z]{%d,}' % self.amount_uppercase | ||||||
|  |         if self.amount_symbols > 0: | ||||||
|  |             filter_regex += r'[%s]{%d,}' % (self.symbol_charset, self.amount_symbols) | ||||||
|  |         result = bool(re.compile(filter_regex).match(password)) | ||||||
|  |         LOGGER.debug("User got %r", result) | ||||||
|  |         return result | ||||||
|  |  | ||||||
|  |     class Meta: | ||||||
|  |  | ||||||
|  |         verbose_name = _('Password Policy Rule') | ||||||
|  |         verbose_name_plural = _('Password Policy Rules') | ||||||
|  |  | ||||||
|  |  | ||||||
| @reversion.register() | @reversion.register() | ||||||
| class WebhookRule(Rule): | class WebhookRule(Rule): | ||||||
|     """Rule that asks webhook""" |     """Rule that asks webhook""" | ||||||
|  | |||||||
| @ -9,27 +9,32 @@ from passbook.core.models import Rule, User | |||||||
| LOGGER = getLogger(__name__) | LOGGER = getLogger(__name__) | ||||||
|  |  | ||||||
| @CELERY_APP.task() | @CELERY_APP.task() | ||||||
| def _rule_engine_task(user_pk, rule_pk): | def _rule_engine_task(user_pk, rule_pk, **kwargs): | ||||||
|     """Task wrapper to run rule checking""" |     """Task wrapper to run rule checking""" | ||||||
|     rule_obj = Rule.objects.filter(pk=rule_pk).select_subclasses().first() |     rule_obj = Rule.objects.filter(pk=rule_pk).select_subclasses().first() | ||||||
|     user_obj = User.objects.get(pk=user_pk) |     user_obj = User.objects.get(pk=user_pk) | ||||||
|  |     for key, value in kwargs.items(): | ||||||
|  |         setattr(user_obj, key, value) | ||||||
|     LOGGER.debug("Running rule `%s`#%s for user %s...", rule_obj.name, rule_obj.pk.hex, user_obj) |     LOGGER.debug("Running rule `%s`#%s for user %s...", rule_obj.name, rule_obj.pk.hex, user_obj) | ||||||
|     return rule_obj.passes(user_obj) |     return rule_obj.passes(user_obj) | ||||||
|  |  | ||||||
| class RuleEngine: | class RuleEngine: | ||||||
|     """Orchestrate rule checking, launch tasks and return result""" |     """Orchestrate rule checking, launch tasks and return result""" | ||||||
|  |  | ||||||
|     _rule_model = None |     rules = None | ||||||
|     _group = None |     _group = None | ||||||
|  |  | ||||||
|     def __init__(self, rule_model): |     def __init__(self, rules): | ||||||
|         self._rule_model = rule_model |         self.rules = rules | ||||||
|  |  | ||||||
|     def for_user(self, user): |     def for_user(self, user): | ||||||
|         """Check rules for user""" |         """Check rules for user""" | ||||||
|         signatures = [] |         signatures = [] | ||||||
|         for rule in self._rule_model.rules.all(): |         kwargs = { | ||||||
|             signatures.append(_rule_engine_task.s(user.pk, rule.pk.hex)) |             '__password__': getattr(user, '__password__') | ||||||
|  |         } | ||||||
|  |         for rule in self.rules: | ||||||
|  |             signatures.append(_rule_engine_task.s(user.pk, rule.pk.hex, **kwargs)) | ||||||
|         self._group = group(signatures)() |         self._group = group(signatures)() | ||||||
|         return self |         return self | ||||||
|  |  | ||||||
|  | |||||||
| @ -12,6 +12,7 @@ https://docs.djangoproject.com/en/2.1/ref/settings/ | |||||||
|  |  | ||||||
| import importlib | import importlib | ||||||
| import os | import os | ||||||
|  | import sys | ||||||
|  |  | ||||||
| from django.contrib import messages | from django.contrib import messages | ||||||
|  |  | ||||||
| @ -33,7 +34,7 @@ SECRET_KEY = CONFIG.get('secret_key') | |||||||
| # SECURITY WARNING: don't run with debug turned on in production! | # SECURITY WARNING: don't run with debug turned on in production! | ||||||
| DEBUG = CONFIG.get('debug') | DEBUG = CONFIG.get('debug') | ||||||
| INTERNAL_IPS = ['127.0.0.1'] | INTERNAL_IPS = ['127.0.0.1'] | ||||||
| ALLOWED_HOSTS = CONFIG.get('domains') | ALLOWED_HOSTS = CONFIG.get('domains', []) | ||||||
|  |  | ||||||
| LOGIN_URL = 'passbook_core:auth-login' | LOGIN_URL = 'passbook_core:auth-login' | ||||||
| # CSRF_FAILURE_VIEW = 'passbook.core.views.errors.CSRFErrorView.as_view' | # CSRF_FAILURE_VIEW = 'passbook.core.views.errors.CSRFErrorView.as_view' | ||||||
| @ -288,6 +289,16 @@ with CONFIG.cd('log'): | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | TEST = False | ||||||
|  | TEST_RUNNER = 'xmlrunner.extra.djangotestrunner.XMLTestRunner' | ||||||
|  | TEST_OUTPUT_VERBOSE = 2 | ||||||
|  |  | ||||||
|  | TEST_OUTPUT_FILE_NAME = 'unittest.xml' | ||||||
|  |  | ||||||
|  | if any('test' in arg for arg in sys.argv): | ||||||
|  |     LOGGING = None | ||||||
|  |     TEST = True | ||||||
|  |  | ||||||
| _DISALLOWED_ITEMS = ['INSTALLED_APPS', 'MIDDLEWARE', 'AUTHENTICATION_BACKENDS'] | _DISALLOWED_ITEMS = ['INSTALLED_APPS', 'MIDDLEWARE', 'AUTHENTICATION_BACKENDS'] | ||||||
| # Load subapps's INSTALLED_APPS | # Load subapps's INSTALLED_APPS | ||||||
| for _app in INSTALLED_APPS: | for _app in INSTALLED_APPS: | ||||||
|  | |||||||
| @ -1,2 +1,2 @@ | |||||||
| """Passbook ldap app Header""" | """Passbook ldap app Header""" | ||||||
| __version__ = '0.0.3-alpha' | __version__ = '0.0.4-alpha' | ||||||
|  | |||||||
| @ -1,2 +1,2 @@ | |||||||
| """passbook lib""" | """passbook lib""" | ||||||
| __version__ = '0.0.1-alpha' | __version__ = '0.0.4-alpha' | ||||||
|  | |||||||
| @ -7,3 +7,4 @@ class PassbookLibConfig(AppConfig): | |||||||
|  |  | ||||||
|     name = 'passbook.lib' |     name = 'passbook.lib' | ||||||
|     label = 'passbook_lib' |     label = 'passbook_lib' | ||||||
|  |     verbose_name = 'passbook lib' | ||||||
|  | |||||||
| @ -1,2 +1,2 @@ | |||||||
| """passbook oauth_client Header""" | """passbook oauth_client Header""" | ||||||
| __version__ = '0.0.3-alpha' | __version__ = '0.0.4-alpha' | ||||||
|  | |||||||
| @ -1,2 +1,2 @@ | |||||||
| """passbook oauth_provider Header""" | """passbook oauth_provider Header""" | ||||||
| __version__ = '0.0.3-alpha' | __version__ = '0.0.4-alpha' | ||||||
|  | |||||||
| @ -1,2 +1,2 @@ | |||||||
| """passbook saml_idp Header""" | """passbook saml_idp Header""" | ||||||
| __version__ = '0.0.3-alpha' | __version__ = '0.0.4-alpha' | ||||||
|  | |||||||
| @ -1,2 +1,2 @@ | |||||||
| """passbook totp Header""" | """passbook totp Header""" | ||||||
| __version__ = '0.0.3-alpha' | __version__ = '0.0.4-alpha' | ||||||
|  | |||||||
| @ -7,3 +7,4 @@ | |||||||
| -r passbook/audit/requirements.txt | -r passbook/audit/requirements.txt | ||||||
| -r passbook/captcha_factor/requirements.txt | -r passbook/captcha_factor/requirements.txt | ||||||
| -r passbook/admin/requirements.txt | -r passbook/admin/requirements.txt | ||||||
|  | -r passbook/api/requirements.txt | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	