outposts: improve API validation for config attribute, ensure all required attributes are set
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
8eaaaae2a7
commit
cd629dfbaa
|
@ -1,23 +1,33 @@
|
||||||
"""Outpost API Views"""
|
"""Outpost API Views"""
|
||||||
|
from dacite.core import from_dict
|
||||||
|
from dacite.exceptions import DaciteError
|
||||||
from drf_yasg.utils import swagger_auto_schema
|
from drf_yasg.utils import swagger_auto_schema
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.fields import BooleanField, CharField, DateTimeField
|
from rest_framework.fields import BooleanField, CharField, DateTimeField
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.serializers import JSONField, ModelSerializer
|
from rest_framework.serializers import JSONField, ModelSerializer, ValidationError
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
from authentik.core.api.providers import ProviderSerializer
|
from authentik.core.api.providers import ProviderSerializer
|
||||||
from authentik.core.api.utils import PassiveSerializer, is_dict
|
from authentik.core.api.utils import PassiveSerializer, is_dict
|
||||||
from authentik.outposts.models import Outpost, default_outpost_config
|
from authentik.outposts.models import Outpost, OutpostConfig, default_outpost_config
|
||||||
|
|
||||||
|
|
||||||
class OutpostSerializer(ModelSerializer):
|
class OutpostSerializer(ModelSerializer):
|
||||||
"""Outpost Serializer"""
|
"""Outpost Serializer"""
|
||||||
|
|
||||||
_config = JSONField(validators=[is_dict])
|
config = JSONField(validators=[is_dict], source="_config")
|
||||||
providers_obj = ProviderSerializer(source="providers", many=True, read_only=True)
|
providers_obj = ProviderSerializer(source="providers", many=True, read_only=True)
|
||||||
|
|
||||||
|
def validate_config(self, config) -> dict:
|
||||||
|
"""Check that the config has all required fields"""
|
||||||
|
try:
|
||||||
|
from_dict(OutpostConfig, config)
|
||||||
|
except DaciteError as exc:
|
||||||
|
raise ValidationError(f"Failed to validate config: {str(exc)}") from exc
|
||||||
|
return config
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
model = Outpost
|
model = Outpost
|
||||||
|
@ -29,7 +39,7 @@ class OutpostSerializer(ModelSerializer):
|
||||||
"providers_obj",
|
"providers_obj",
|
||||||
"service_connection",
|
"service_connection",
|
||||||
"token_identifier",
|
"token_identifier",
|
||||||
"_config",
|
"config",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,10 @@ from django.urls import reverse
|
||||||
from rest_framework.test import APITestCase
|
from rest_framework.test import APITestCase
|
||||||
|
|
||||||
from authentik.core.models import PropertyMapping, User
|
from authentik.core.models import PropertyMapping, User
|
||||||
|
from authentik.flows.models import Flow
|
||||||
|
from authentik.outposts.api.outposts import OutpostSerializer
|
||||||
|
from authentik.outposts.models import default_outpost_config
|
||||||
|
from authentik.providers.proxy.models import ProxyProvider
|
||||||
|
|
||||||
|
|
||||||
class TestOutpostServiceConnectionsAPI(APITestCase):
|
class TestOutpostServiceConnectionsAPI(APITestCase):
|
||||||
|
@ -22,3 +26,20 @@ class TestOutpostServiceConnectionsAPI(APITestCase):
|
||||||
reverse("authentik_api:outpostserviceconnection-types"),
|
reverse("authentik_api:outpostserviceconnection-types"),
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_outpost_config(self):
|
||||||
|
"""Test Outpost's config field"""
|
||||||
|
provider = ProxyProvider.objects.create(name="test", authorization_flow=Flow.objects.first())
|
||||||
|
invalid = OutpostSerializer(data={
|
||||||
|
"name": "foo",
|
||||||
|
"providers": [provider.pk],
|
||||||
|
"config": {}
|
||||||
|
})
|
||||||
|
self.assertFalse(invalid.is_valid())
|
||||||
|
self.assertIn("config", invalid.errors)
|
||||||
|
valid = OutpostSerializer(data={
|
||||||
|
"name": "foo",
|
||||||
|
"providers": [provider.pk],
|
||||||
|
"config": default_outpost_config("foo")
|
||||||
|
})
|
||||||
|
self.assertTrue(valid.is_valid())
|
||||||
|
|
|
@ -16198,7 +16198,7 @@ definitions:
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
- providers
|
- providers
|
||||||
- _config
|
- config
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
pk:
|
pk:
|
||||||
|
@ -16237,8 +16237,8 @@ definitions:
|
||||||
title: Token identifier
|
title: Token identifier
|
||||||
type: string
|
type: string
|
||||||
readOnly: true
|
readOnly: true
|
||||||
_config:
|
config:
|
||||||
title: config
|
title: Config
|
||||||
type: object
|
type: object
|
||||||
OutpostDefaultConfig:
|
OutpostDefaultConfig:
|
||||||
type: object
|
type: object
|
||||||
|
|
|
@ -102,18 +102,18 @@ export class OutpostForm extends Form<Outpost> {
|
||||||
</select>
|
</select>
|
||||||
<p class="pf-c-form__helper-text">${t`Hold control/command to select multiple items.`}</p>
|
<p class="pf-c-form__helper-text">${t`Hold control/command to select multiple items.`}</p>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
${until(new OutpostsApi(DEFAULT_CONFIG).outpostsOutpostsDefaultSettings({}).then(config => {
|
<ak-form-element-horizontal
|
||||||
let fc = config.config;
|
label=${t`Configuration`}
|
||||||
if (this.outpost) {
|
name="config">
|
||||||
fc = this.outpost.config;
|
<ak-codemirror mode="yaml" value="${until(new OutpostsApi(DEFAULT_CONFIG).outpostsOutpostsDefaultSettings({}).then(config => {
|
||||||
}
|
let fc = config.config;
|
||||||
return html`<ak-form-element-horizontal
|
if (this.outpost) {
|
||||||
label=${t`Configuration`}
|
fc = this.outpost.config;
|
||||||
name="config">
|
}
|
||||||
<ak-codemirror mode="yaml" value="${YAML.stringify(fc)}"></ak-codemirror>
|
return YAML.stringify(fc);
|
||||||
<p class="pf-c-form__helper-text">${t`Set custom attributes using YAML or JSON.`}</p>
|
}))}"></ak-codemirror>
|
||||||
</ak-form-element-horizontal>`;
|
<p class="pf-c-form__helper-text">${t`Set custom attributes using YAML or JSON.`}</p>
|
||||||
}))}
|
</ak-form-element-horizontal>
|
||||||
</form>`;
|
</form>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue