diff --git a/passbook/core/models.py b/passbook/core/models.py index f5b757e3f..26c21b33d 100644 --- a/passbook/core/models.py +++ b/passbook/core/models.py @@ -20,12 +20,24 @@ class User(AbstractUser): @reversion.register() class Provider(models.Model): - """Application-independant Provider instance. For example SAML2 Remote, OAuth2 Application""" + """Application-independent Provider instance. For example SAML2 Remote, OAuth2 Application""" # This class defines no field for easier inheritance +class RuleModel(UUIDModel, CreatedUpdatedModel): + """Base model which can have rules applied to it""" + + rules = models.ManyToManyField('Rule') + + def passes(self, user: User) -> bool: + """Return true if user passes, otherwise False or raise Exception""" + for rule in self.rules: + if not rule.passes(user): + return False + return True + @reversion.register() -class Application(UUIDModel, CreatedUpdatedModel): +class Application(RuleModel): """Every Application which uses passbook for authentication/identification/authorization needs an Application record. Other authentication types can subclass this Model to add custom fields and other properties""" @@ -45,7 +57,7 @@ class Application(UUIDModel, CreatedUpdatedModel): return self.name @reversion.register() -class Source(UUIDModel, CreatedUpdatedModel): +class Source(RuleModel): """Base Authentication source, i.e. an OAuth Provider, SAML Remote or LDAP Server""" name = models.TextField() @@ -82,7 +94,6 @@ class Rule(UUIDModel, CreatedUpdatedModel): ) name = models.TextField(blank=True, null=True) - application = models.ForeignKey(Application, on_delete=models.CASCADE) action = models.CharField(max_length=20, choices=ACTIONS) negate = models.BooleanField(default=False) @@ -91,9 +102,9 @@ class Rule(UUIDModel, CreatedUpdatedModel): def __str__(self): if self.name: return self.name - return "%s action %s" % (self.application, self.action) + return "%s action %s" % (self.name, self.action) - def user_passes(self, user: User) -> bool: + def passes(self, user: User) -> bool: """Check if user instance passes this rule""" raise NotImplementedError() @@ -120,13 +131,13 @@ class FieldMatcherRule(Rule): value = models.TextField() def __str__(self): - description = "app %s, user.%s %s '%s'" % (self.application, self.user_field, - self.match_action, self.value) + description = "%s, user.%s %s '%s'" % (self.name, self.user_field, + self.match_action, self.value) if self.name: description = "%s: %s" % (self.name, description) return description - def user_passes(self, user: User) -> bool: + def passes(self, user: User) -> bool: """Check if user instance passes this role""" if not hasattr(user, self.user_field): raise ValueError("Field does not exist") diff --git a/passbook/core/requirements.txt b/passbook/core/requirements.txt index 0c22aad72..19b8526dc 100644 --- a/passbook/core/requirements.txt +++ b/passbook/core/requirements.txt @@ -1,8 +1,9 @@ django>=2.0 django-reversion +django-model-utils +django-crispy-forms +djangorestframework PyYAML raven -djangorestframework markdown -django-model-utils colorlog \ No newline at end of file diff --git a/passbook/core/settings.py b/passbook/core/settings.py index 56b2c3246..58a58e041 100644 --- a/passbook/core/settings.py +++ b/passbook/core/settings.py @@ -54,8 +54,10 @@ INSTALLED_APPS = [ 'django.contrib.staticfiles', 'reversion', 'rest_framework', + 'crispy_forms', 'passbook.core', 'passbook.admin', + 'passbook.audit', 'passbook.lib', 'passbook.ldap', 'passbook.oauth_client', diff --git a/passbook/core/templates/overview/base.html b/passbook/core/templates/overview/base.html index 8d7806d53..ddee7516b 100644 --- a/passbook/core/templates/overview/base.html +++ b/passbook/core/templates/overview/base.html @@ -53,8 +53,8 @@ -