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.dummy.api import DummyPolicyViewSet
|
||||||
from passbook.policies.expiry.api import PasswordExpiryPolicyViewSet
|
from passbook.policies.expiry.api import PasswordExpiryPolicyViewSet
|
||||||
from passbook.policies.expression.api import ExpressionPolicyViewSet
|
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.hibp.api import HaveIBeenPwendPolicyViewSet
|
||||||
from passbook.policies.password.api import PasswordPolicyViewSet
|
from passbook.policies.password.api import PasswordPolicyViewSet
|
||||||
from passbook.policies.reputation.api import ReputationPolicyViewSet
|
from passbook.policies.reputation.api import ReputationPolicyViewSet
|
||||||
|
@ -71,9 +72,10 @@ router.register("sources/oauth", OAuthSourceViewSet)
|
||||||
router.register("policies/all", PolicyViewSet)
|
router.register("policies/all", PolicyViewSet)
|
||||||
router.register("policies/bindings", PolicyBindingViewSet)
|
router.register("policies/bindings", PolicyBindingViewSet)
|
||||||
router.register("policies/expression", ExpressionPolicyViewSet)
|
router.register("policies/expression", ExpressionPolicyViewSet)
|
||||||
|
router.register("policies/group_membership", GroupMembershipPolicyViewSet)
|
||||||
router.register("policies/haveibeenpwned", HaveIBeenPwendPolicyViewSet)
|
router.register("policies/haveibeenpwned", HaveIBeenPwendPolicyViewSet)
|
||||||
|
router.register("policies/password_expiry", PasswordExpiryPolicyViewSet)
|
||||||
router.register("policies/password", PasswordPolicyViewSet)
|
router.register("policies/password", PasswordPolicyViewSet)
|
||||||
router.register("policies/passwordexpiry", PasswordExpiryPolicyViewSet)
|
|
||||||
router.register("policies/reputation", ReputationPolicyViewSet)
|
router.register("policies/reputation", ReputationPolicyViewSet)
|
||||||
|
|
||||||
router.register("providers/all", ProviderViewSet)
|
router.register("providers/all", ProviderViewSet)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.admin.widgets import FilteredSelectMultiple
|
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||||
|
|
||||||
|
from passbook.admin.fields import CodeMirrorWidget, YAMLField
|
||||||
from passbook.core.models import Group, User
|
from passbook.core.models import Group, User
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,4 +35,8 @@ class GroupForm(forms.ModelForm):
|
||||||
fields = ["name", "parent", "members", "attributes"]
|
fields = ["name", "parent", "members", "attributes"]
|
||||||
widgets = {
|
widgets = {
|
||||||
"name": forms.TextInput(),
|
"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.serializers import ModelSerializer
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ class PasswordPolicySerializer(ModelSerializer):
|
||||||
|
|
||||||
|
|
||||||
class PasswordPolicyViewSet(ModelViewSet):
|
class PasswordPolicyViewSet(ModelViewSet):
|
||||||
"""Source Viewset"""
|
"""Password Policy Viewset"""
|
||||||
|
|
||||||
queryset = PasswordPolicy.objects.all()
|
queryset = PasswordPolicy.objects.all()
|
||||||
serializer_class = PasswordPolicySerializer
|
serializer_class = PasswordPolicySerializer
|
||||||
|
|
|
@ -86,6 +86,7 @@ INSTALLED_APPS = [
|
||||||
"passbook.policies.expression.apps.PassbookPolicyExpressionConfig",
|
"passbook.policies.expression.apps.PassbookPolicyExpressionConfig",
|
||||||
"passbook.policies.hibp.apps.PassbookPolicyHIBPConfig",
|
"passbook.policies.hibp.apps.PassbookPolicyHIBPConfig",
|
||||||
"passbook.policies.password.apps.PassbookPoliciesPasswordConfig",
|
"passbook.policies.password.apps.PassbookPoliciesPasswordConfig",
|
||||||
|
"passbook.policies.group_membership.apps.PassbookPoliciesGroupMembershipConfig",
|
||||||
"passbook.policies.reputation.apps.PassbookPolicyReputationConfig",
|
"passbook.policies.reputation.apps.PassbookPolicyReputationConfig",
|
||||||
"passbook.providers.app_gw.apps.PassbookApplicationApplicationGatewayConfig",
|
"passbook.providers.app_gw.apps.PassbookApplicationApplicationGatewayConfig",
|
||||||
"passbook.providers.oauth.apps.PassbookProviderOAuthConfig",
|
"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
|
required: true
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
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/:
|
/policies/haveibeenpwned/:
|
||||||
get:
|
get:
|
||||||
operationId: policies_haveibeenpwned_list
|
operationId: policies_haveibeenpwned_list
|
||||||
|
@ -1352,7 +1479,7 @@ paths:
|
||||||
/policies/password/:
|
/policies/password/:
|
||||||
get:
|
get:
|
||||||
operationId: policies_password_list
|
operationId: policies_password_list
|
||||||
description: Source Viewset
|
description: Password Policy Viewset
|
||||||
parameters:
|
parameters:
|
||||||
- name: ordering
|
- name: ordering
|
||||||
in: query
|
in: query
|
||||||
|
@ -1401,7 +1528,7 @@ paths:
|
||||||
- policies
|
- policies
|
||||||
post:
|
post:
|
||||||
operationId: policies_password_create
|
operationId: policies_password_create
|
||||||
description: Source Viewset
|
description: Password Policy Viewset
|
||||||
parameters:
|
parameters:
|
||||||
- name: data
|
- name: data
|
||||||
in: body
|
in: body
|
||||||
|
@ -1419,7 +1546,7 @@ paths:
|
||||||
/policies/password/{policy_uuid}/:
|
/policies/password/{policy_uuid}/:
|
||||||
get:
|
get:
|
||||||
operationId: policies_password_read
|
operationId: policies_password_read
|
||||||
description: Source Viewset
|
description: Password Policy Viewset
|
||||||
parameters: []
|
parameters: []
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
|
@ -1430,7 +1557,7 @@ paths:
|
||||||
- policies
|
- policies
|
||||||
put:
|
put:
|
||||||
operationId: policies_password_update
|
operationId: policies_password_update
|
||||||
description: Source Viewset
|
description: Password Policy Viewset
|
||||||
parameters:
|
parameters:
|
||||||
- name: data
|
- name: data
|
||||||
in: body
|
in: body
|
||||||
|
@ -1446,7 +1573,7 @@ paths:
|
||||||
- policies
|
- policies
|
||||||
patch:
|
patch:
|
||||||
operationId: policies_password_partial_update
|
operationId: policies_password_partial_update
|
||||||
description: Source Viewset
|
description: Password Policy Viewset
|
||||||
parameters:
|
parameters:
|
||||||
- name: data
|
- name: data
|
||||||
in: body
|
in: body
|
||||||
|
@ -1462,7 +1589,7 @@ paths:
|
||||||
- policies
|
- policies
|
||||||
delete:
|
delete:
|
||||||
operationId: policies_password_delete
|
operationId: policies_password_delete
|
||||||
description: Source Viewset
|
description: Password Policy Viewset
|
||||||
parameters: []
|
parameters: []
|
||||||
responses:
|
responses:
|
||||||
'204':
|
'204':
|
||||||
|
@ -1476,9 +1603,9 @@ paths:
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
/policies/passwordexpiry/:
|
/policies/password_expiry/:
|
||||||
get:
|
get:
|
||||||
operationId: policies_passwordexpiry_list
|
operationId: policies_password_expiry_list
|
||||||
description: Password Expiry Viewset
|
description: Password Expiry Viewset
|
||||||
parameters:
|
parameters:
|
||||||
- name: ordering
|
- name: ordering
|
||||||
|
@ -1527,7 +1654,7 @@ paths:
|
||||||
tags:
|
tags:
|
||||||
- policies
|
- policies
|
||||||
post:
|
post:
|
||||||
operationId: policies_passwordexpiry_create
|
operationId: policies_password_expiry_create
|
||||||
description: Password Expiry Viewset
|
description: Password Expiry Viewset
|
||||||
parameters:
|
parameters:
|
||||||
- name: data
|
- name: data
|
||||||
|
@ -1543,9 +1670,9 @@ paths:
|
||||||
tags:
|
tags:
|
||||||
- policies
|
- policies
|
||||||
parameters: []
|
parameters: []
|
||||||
/policies/passwordexpiry/{policy_uuid}/:
|
/policies/password_expiry/{policy_uuid}/:
|
||||||
get:
|
get:
|
||||||
operationId: policies_passwordexpiry_read
|
operationId: policies_password_expiry_read
|
||||||
description: Password Expiry Viewset
|
description: Password Expiry Viewset
|
||||||
parameters: []
|
parameters: []
|
||||||
responses:
|
responses:
|
||||||
|
@ -1556,7 +1683,7 @@ paths:
|
||||||
tags:
|
tags:
|
||||||
- policies
|
- policies
|
||||||
put:
|
put:
|
||||||
operationId: policies_passwordexpiry_update
|
operationId: policies_password_expiry_update
|
||||||
description: Password Expiry Viewset
|
description: Password Expiry Viewset
|
||||||
parameters:
|
parameters:
|
||||||
- name: data
|
- name: data
|
||||||
|
@ -1572,7 +1699,7 @@ paths:
|
||||||
tags:
|
tags:
|
||||||
- policies
|
- policies
|
||||||
patch:
|
patch:
|
||||||
operationId: policies_passwordexpiry_partial_update
|
operationId: policies_password_expiry_partial_update
|
||||||
description: Password Expiry Viewset
|
description: Password Expiry Viewset
|
||||||
parameters:
|
parameters:
|
||||||
- name: data
|
- name: data
|
||||||
|
@ -1588,7 +1715,7 @@ paths:
|
||||||
tags:
|
tags:
|
||||||
- policies
|
- policies
|
||||||
delete:
|
delete:
|
||||||
operationId: policies_passwordexpiry_delete
|
operationId: policies_password_expiry_delete
|
||||||
description: Password Expiry Viewset
|
description: Password Expiry Viewset
|
||||||
parameters: []
|
parameters: []
|
||||||
responses:
|
responses:
|
||||||
|
@ -5661,6 +5788,23 @@ definitions:
|
||||||
title: Expression
|
title: Expression
|
||||||
type: string
|
type: string
|
||||||
minLength: 1
|
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:
|
HaveIBeenPwendPolicy:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|
Reference in New Issue