root: add group_membership policy
This commit is contained in:
parent
3478a2cf6d
commit
6634cc2edf
|
@ -21,6 +21,7 @@ from passbook.policies.api import PolicyBindingViewSet, PolicyViewSet
|
|||
from passbook.policies.dummy.api import DummyPolicyViewSet
|
||||
from passbook.policies.expiry.api import PasswordExpiryPolicyViewSet
|
||||
from passbook.policies.expression.api import ExpressionPolicyViewSet
|
||||
from passbook.policies.group_membership.api import GroupMembershipPolicyViewSet
|
||||
from passbook.policies.hibp.api import HaveIBeenPwendPolicyViewSet
|
||||
from passbook.policies.password.api import PasswordPolicyViewSet
|
||||
from passbook.policies.reputation.api import ReputationPolicyViewSet
|
||||
|
@ -71,9 +72,10 @@ router.register("sources/oauth", OAuthSourceViewSet)
|
|||
router.register("policies/all", PolicyViewSet)
|
||||
router.register("policies/bindings", PolicyBindingViewSet)
|
||||
router.register("policies/expression", ExpressionPolicyViewSet)
|
||||
router.register("policies/group_membership", GroupMembershipPolicyViewSet)
|
||||
router.register("policies/haveibeenpwned", HaveIBeenPwendPolicyViewSet)
|
||||
router.register("policies/password_expiry", PasswordExpiryPolicyViewSet)
|
||||
router.register("policies/password", PasswordPolicyViewSet)
|
||||
router.register("policies/passwordexpiry", PasswordExpiryPolicyViewSet)
|
||||
router.register("policies/reputation", ReputationPolicyViewSet)
|
||||
|
||||
router.register("providers/all", ProviderViewSet)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
from django import forms
|
||||
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||
|
||||
from passbook.admin.fields import CodeMirrorWidget, YAMLField
|
||||
from passbook.core.models import Group, User
|
||||
|
||||
|
||||
|
@ -34,4 +35,8 @@ class GroupForm(forms.ModelForm):
|
|||
fields = ["name", "parent", "members", "attributes"]
|
||||
widgets = {
|
||||
"name": forms.TextInput(),
|
||||
"attributes": CodeMirrorWidget,
|
||||
}
|
||||
field_classes = {
|
||||
"attributes": YAMLField,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
"""Group Membership Policy API"""
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from passbook.policies.forms import GENERAL_SERIALIZER_FIELDS
|
||||
from passbook.policies.group_membership.models import GroupMembershipPolicy
|
||||
|
||||
|
||||
class GroupMembershipPolicySerializer(ModelSerializer):
|
||||
"""Group Membership Policy Serializer"""
|
||||
|
||||
class Meta:
|
||||
model = GroupMembershipPolicy
|
||||
fields = GENERAL_SERIALIZER_FIELDS + [
|
||||
"group",
|
||||
]
|
||||
|
||||
|
||||
class GroupMembershipPolicyViewSet(ModelViewSet):
|
||||
"""Group Membership Policy Viewset"""
|
||||
|
||||
queryset = GroupMembershipPolicy.objects.all()
|
||||
serializer_class = GroupMembershipPolicySerializer
|
|
@ -0,0 +1,11 @@
|
|||
"""passbook Group Membership policy app config"""
|
||||
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class PassbookPoliciesGroupMembershipConfig(AppConfig):
|
||||
"""passbook Group Membership policy app config"""
|
||||
|
||||
name = "passbook.policies.group_membership"
|
||||
label = "passbook_policies_group_membership"
|
||||
verbose_name = "passbook Policies.Group Membership"
|
|
@ -0,0 +1,20 @@
|
|||
"""passbook Group Membership Policy forms"""
|
||||
|
||||
from django import forms
|
||||
|
||||
from passbook.policies.forms import GENERAL_FIELDS
|
||||
from passbook.policies.group_membership.models import GroupMembershipPolicy
|
||||
|
||||
|
||||
class GroupMembershipPolicyForm(forms.ModelForm):
|
||||
"""GroupMembershipPolicy Form"""
|
||||
|
||||
class Meta:
|
||||
|
||||
model = GroupMembershipPolicy
|
||||
fields = GENERAL_FIELDS + [
|
||||
"group",
|
||||
]
|
||||
widgets = {
|
||||
"name": forms.TextInput(),
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
# Generated by Django 3.0.7 on 2020-07-01 19:01
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
("passbook_policies", "0002_auto_20200528_1647"),
|
||||
("passbook_core", "0003_default_user"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="GroupMembershipPolicy",
|
||||
fields=[
|
||||
(
|
||||
"policy_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="passbook_policies.Policy",
|
||||
),
|
||||
),
|
||||
(
|
||||
"group",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to="passbook_core.Group",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Group Membership Policy",
|
||||
"verbose_name_plural": "Group Membership Policies",
|
||||
},
|
||||
bases=("passbook_policies.policy",),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,23 @@
|
|||
"""user field matcher models"""
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from passbook.core.models import Group
|
||||
from passbook.policies.models import Policy
|
||||
from passbook.policies.types import PolicyRequest, PolicyResult
|
||||
|
||||
|
||||
class GroupMembershipPolicy(Policy):
|
||||
"""Check that the user is member of the selected group."""
|
||||
|
||||
group = models.ForeignKey(Group, null=True, blank=True, on_delete=models.SET_NULL)
|
||||
|
||||
form = "passbook.policies.group_membership.forms.GroupMembershipPolicyForm"
|
||||
|
||||
def passes(self, request: PolicyRequest) -> PolicyResult:
|
||||
return PolicyResult(self.group.user_set.filter(pk=request.user.pk).exists())
|
||||
|
||||
class Meta:
|
||||
|
||||
verbose_name = _("Group Membership Policy")
|
||||
verbose_name_plural = _("Group Membership Policies")
|
|
@ -0,0 +1,32 @@
|
|||
"""evaluator tests"""
|
||||
from django.test import TestCase
|
||||
from guardian.shortcuts import get_anonymous_user
|
||||
|
||||
from passbook.core.models import Group
|
||||
from passbook.policies.group_membership.models import GroupMembershipPolicy
|
||||
from passbook.policies.types import PolicyRequest
|
||||
|
||||
|
||||
class TestGroupMembershipPolicy(TestCase):
|
||||
"""GroupMembershipPolicy tests"""
|
||||
|
||||
def setUp(self):
|
||||
self.request = PolicyRequest(user=get_anonymous_user())
|
||||
|
||||
def test_invalid(self):
|
||||
"""user not in group"""
|
||||
group = Group.objects.create(name="test")
|
||||
policy: GroupMembershipPolicy = GroupMembershipPolicy.objects.create(
|
||||
group=group
|
||||
)
|
||||
self.assertFalse(policy.passes(self.request).passing)
|
||||
|
||||
def test_valid(self):
|
||||
"""user in group"""
|
||||
group = Group.objects.create(name="test")
|
||||
group.user_set.add(get_anonymous_user())
|
||||
group.save()
|
||||
policy: GroupMembershipPolicy = GroupMembershipPolicy.objects.create(
|
||||
group=group
|
||||
)
|
||||
self.assertTrue(policy.passes(self.request).passing)
|
|
@ -1,4 +1,4 @@
|
|||
"""Source API Views"""
|
||||
"""Password Policy API Views"""
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
|
@ -22,7 +22,7 @@ class PasswordPolicySerializer(ModelSerializer):
|
|||
|
||||
|
||||
class PasswordPolicyViewSet(ModelViewSet):
|
||||
"""Source Viewset"""
|
||||
"""Password Policy Viewset"""
|
||||
|
||||
queryset = PasswordPolicy.objects.all()
|
||||
serializer_class = PasswordPolicySerializer
|
||||
|
|
|
@ -86,6 +86,7 @@ INSTALLED_APPS = [
|
|||
"passbook.policies.expression.apps.PassbookPolicyExpressionConfig",
|
||||
"passbook.policies.hibp.apps.PassbookPolicyHIBPConfig",
|
||||
"passbook.policies.password.apps.PassbookPoliciesPasswordConfig",
|
||||
"passbook.policies.group_membership.apps.PassbookPoliciesGroupMembershipConfig",
|
||||
"passbook.policies.reputation.apps.PassbookPolicyReputationConfig",
|
||||
"passbook.providers.app_gw.apps.PassbookApplicationApplicationGatewayConfig",
|
||||
"passbook.providers.oauth.apps.PassbookProviderOAuthConfig",
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 3.0.7 on 2020-07-01 19:00
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("passbook_stages_otp_time", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="otptimestage",
|
||||
name="digits",
|
||||
field=models.IntegerField(
|
||||
choices=[
|
||||
(6, "6 digits, widely compatible"),
|
||||
(8, "8 digits, not compatible with apps like Google Authenticator"),
|
||||
]
|
||||
),
|
||||
),
|
||||
]
|
172
swagger.yaml
172
swagger.yaml
|
@ -1222,6 +1222,133 @@ paths:
|
|||
required: true
|
||||
type: string
|
||||
format: uuid
|
||||
/policies/group_membership/:
|
||||
get:
|
||||
operationId: policies_group_membership_list
|
||||
description: Group Membership Policy Viewset
|
||||
parameters:
|
||||
- name: ordering
|
||||
in: query
|
||||
description: Which field to use when ordering the results.
|
||||
required: false
|
||||
type: string
|
||||
- name: search
|
||||
in: query
|
||||
description: A search term.
|
||||
required: false
|
||||
type: string
|
||||
- name: limit
|
||||
in: query
|
||||
description: Number of results to return per page.
|
||||
required: false
|
||||
type: integer
|
||||
- name: offset
|
||||
in: query
|
||||
description: The initial index from which to return the results.
|
||||
required: false
|
||||
type: integer
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
schema:
|
||||
required:
|
||||
- count
|
||||
- results
|
||||
type: object
|
||||
properties:
|
||||
count:
|
||||
type: integer
|
||||
next:
|
||||
type: string
|
||||
format: uri
|
||||
x-nullable: true
|
||||
previous:
|
||||
type: string
|
||||
format: uri
|
||||
x-nullable: true
|
||||
results:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/GroupMembershipPolicy'
|
||||
tags:
|
||||
- policies
|
||||
post:
|
||||
operationId: policies_group_membership_create
|
||||
description: Group Membership Policy Viewset
|
||||
parameters:
|
||||
- name: data
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/GroupMembershipPolicy'
|
||||
responses:
|
||||
'201':
|
||||
description: ''
|
||||
schema:
|
||||
$ref: '#/definitions/GroupMembershipPolicy'
|
||||
tags:
|
||||
- policies
|
||||
parameters: []
|
||||
/policies/group_membership/{policy_uuid}/:
|
||||
get:
|
||||
operationId: policies_group_membership_read
|
||||
description: Group Membership Policy Viewset
|
||||
parameters: []
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
schema:
|
||||
$ref: '#/definitions/GroupMembershipPolicy'
|
||||
tags:
|
||||
- policies
|
||||
put:
|
||||
operationId: policies_group_membership_update
|
||||
description: Group Membership Policy Viewset
|
||||
parameters:
|
||||
- name: data
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/GroupMembershipPolicy'
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
schema:
|
||||
$ref: '#/definitions/GroupMembershipPolicy'
|
||||
tags:
|
||||
- policies
|
||||
patch:
|
||||
operationId: policies_group_membership_partial_update
|
||||
description: Group Membership Policy Viewset
|
||||
parameters:
|
||||
- name: data
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/GroupMembershipPolicy'
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
schema:
|
||||
$ref: '#/definitions/GroupMembershipPolicy'
|
||||
tags:
|
||||
- policies
|
||||
delete:
|
||||
operationId: policies_group_membership_delete
|
||||
description: Group Membership Policy Viewset
|
||||
parameters: []
|
||||
responses:
|
||||
'204':
|
||||
description: ''
|
||||
tags:
|
||||
- policies
|
||||
parameters:
|
||||
- name: policy_uuid
|
||||
in: path
|
||||
description: A UUID string identifying this Group Membership Policy.
|
||||
required: true
|
||||
type: string
|
||||
format: uuid
|
||||
/policies/haveibeenpwned/:
|
||||
get:
|
||||
operationId: policies_haveibeenpwned_list
|
||||
|
@ -1352,7 +1479,7 @@ paths:
|
|||
/policies/password/:
|
||||
get:
|
||||
operationId: policies_password_list
|
||||
description: Source Viewset
|
||||
description: Password Policy Viewset
|
||||
parameters:
|
||||
- name: ordering
|
||||
in: query
|
||||
|
@ -1401,7 +1528,7 @@ paths:
|
|||
- policies
|
||||
post:
|
||||
operationId: policies_password_create
|
||||
description: Source Viewset
|
||||
description: Password Policy Viewset
|
||||
parameters:
|
||||
- name: data
|
||||
in: body
|
||||
|
@ -1419,7 +1546,7 @@ paths:
|
|||
/policies/password/{policy_uuid}/:
|
||||
get:
|
||||
operationId: policies_password_read
|
||||
description: Source Viewset
|
||||
description: Password Policy Viewset
|
||||
parameters: []
|
||||
responses:
|
||||
'200':
|
||||
|
@ -1430,7 +1557,7 @@ paths:
|
|||
- policies
|
||||
put:
|
||||
operationId: policies_password_update
|
||||
description: Source Viewset
|
||||
description: Password Policy Viewset
|
||||
parameters:
|
||||
- name: data
|
||||
in: body
|
||||
|
@ -1446,7 +1573,7 @@ paths:
|
|||
- policies
|
||||
patch:
|
||||
operationId: policies_password_partial_update
|
||||
description: Source Viewset
|
||||
description: Password Policy Viewset
|
||||
parameters:
|
||||
- name: data
|
||||
in: body
|
||||
|
@ -1462,7 +1589,7 @@ paths:
|
|||
- policies
|
||||
delete:
|
||||
operationId: policies_password_delete
|
||||
description: Source Viewset
|
||||
description: Password Policy Viewset
|
||||
parameters: []
|
||||
responses:
|
||||
'204':
|
||||
|
@ -1476,9 +1603,9 @@ paths:
|
|||
required: true
|
||||
type: string
|
||||
format: uuid
|
||||
/policies/passwordexpiry/:
|
||||
/policies/password_expiry/:
|
||||
get:
|
||||
operationId: policies_passwordexpiry_list
|
||||
operationId: policies_password_expiry_list
|
||||
description: Password Expiry Viewset
|
||||
parameters:
|
||||
- name: ordering
|
||||
|
@ -1527,7 +1654,7 @@ paths:
|
|||
tags:
|
||||
- policies
|
||||
post:
|
||||
operationId: policies_passwordexpiry_create
|
||||
operationId: policies_password_expiry_create
|
||||
description: Password Expiry Viewset
|
||||
parameters:
|
||||
- name: data
|
||||
|
@ -1543,9 +1670,9 @@ paths:
|
|||
tags:
|
||||
- policies
|
||||
parameters: []
|
||||
/policies/passwordexpiry/{policy_uuid}/:
|
||||
/policies/password_expiry/{policy_uuid}/:
|
||||
get:
|
||||
operationId: policies_passwordexpiry_read
|
||||
operationId: policies_password_expiry_read
|
||||
description: Password Expiry Viewset
|
||||
parameters: []
|
||||
responses:
|
||||
|
@ -1556,7 +1683,7 @@ paths:
|
|||
tags:
|
||||
- policies
|
||||
put:
|
||||
operationId: policies_passwordexpiry_update
|
||||
operationId: policies_password_expiry_update
|
||||
description: Password Expiry Viewset
|
||||
parameters:
|
||||
- name: data
|
||||
|
@ -1572,7 +1699,7 @@ paths:
|
|||
tags:
|
||||
- policies
|
||||
patch:
|
||||
operationId: policies_passwordexpiry_partial_update
|
||||
operationId: policies_password_expiry_partial_update
|
||||
description: Password Expiry Viewset
|
||||
parameters:
|
||||
- name: data
|
||||
|
@ -1588,7 +1715,7 @@ paths:
|
|||
tags:
|
||||
- policies
|
||||
delete:
|
||||
operationId: policies_passwordexpiry_delete
|
||||
operationId: policies_password_expiry_delete
|
||||
description: Password Expiry Viewset
|
||||
parameters: []
|
||||
responses:
|
||||
|
@ -5661,6 +5788,23 @@ definitions:
|
|||
title: Expression
|
||||
type: string
|
||||
minLength: 1
|
||||
GroupMembershipPolicy:
|
||||
type: object
|
||||
properties:
|
||||
pk:
|
||||
title: Policy uuid
|
||||
type: string
|
||||
format: uuid
|
||||
readOnly: true
|
||||
name:
|
||||
title: Name
|
||||
type: string
|
||||
x-nullable: true
|
||||
group:
|
||||
title: Group
|
||||
type: string
|
||||
format: uuid
|
||||
x-nullable: true
|
||||
HaveIBeenPwendPolicy:
|
||||
type: object
|
||||
properties:
|
||||
|
|
Reference in New Issue