Compare commits
1 Commits
version/20
...
blueprints
Author | SHA1 | Date | |
---|---|---|---|
906c63c16f |
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -29,6 +29,7 @@
|
|||||||
"!Enumerate sequence",
|
"!Enumerate sequence",
|
||||||
"!Env scalar",
|
"!Env scalar",
|
||||||
"!Find sequence",
|
"!Find sequence",
|
||||||
|
"!FindObject sequence",
|
||||||
"!Format sequence",
|
"!Format sequence",
|
||||||
"!If sequence",
|
"!If sequence",
|
||||||
"!Index scalar",
|
"!Index scalar",
|
||||||
@ -51,7 +52,9 @@
|
|||||||
"ignoreCase": false
|
"ignoreCase": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"go.testFlags": ["-count=1"],
|
"go.testFlags": [
|
||||||
|
"-count=1"
|
||||||
|
],
|
||||||
"github-actions.workflows.pinned.workflows": [
|
"github-actions.workflows.pinned.workflows": [
|
||||||
".github/workflows/ci-main.yml"
|
".github/workflows/ci-main.yml"
|
||||||
]
|
]
|
||||||
|
@ -150,6 +150,7 @@ entries:
|
|||||||
at_index_sequence_default: !AtIndex [!Context sequence, 100, "non existent"]
|
at_index_sequence_default: !AtIndex [!Context sequence, 100, "non existent"]
|
||||||
at_index_mapping: !AtIndex [!Context mapping, "key2"]
|
at_index_mapping: !AtIndex [!Context mapping, "key2"]
|
||||||
at_index_mapping_default: !AtIndex [!Context mapping, "invalid", "non existent"]
|
at_index_mapping_default: !AtIndex [!Context mapping, "invalid", "non existent"]
|
||||||
|
find_object: !AtIndex [!FindObject [authentik_providers_oauth2.scopemapping, [scope_name, openid]], managed]
|
||||||
identifiers:
|
identifiers:
|
||||||
name: test
|
name: test
|
||||||
conditions:
|
conditions:
|
||||||
|
@ -4,6 +4,7 @@ from os import environ
|
|||||||
|
|
||||||
from django.test import TransactionTestCase
|
from django.test import TransactionTestCase
|
||||||
|
|
||||||
|
from authentik.blueprints.tests import apply_blueprint
|
||||||
from authentik.blueprints.v1.exporter import FlowExporter
|
from authentik.blueprints.v1.exporter import FlowExporter
|
||||||
from authentik.blueprints.v1.importer import Importer, transaction_rollback
|
from authentik.blueprints.v1.importer import Importer, transaction_rollback
|
||||||
from authentik.core.models import Group
|
from authentik.core.models import Group
|
||||||
@ -126,6 +127,7 @@ class TestBlueprintsV1(TransactionTestCase):
|
|||||||
|
|
||||||
self.assertEqual(Prompt.objects.filter(field_key="username").count(), count_before)
|
self.assertEqual(Prompt.objects.filter(field_key="username").count(), count_before)
|
||||||
|
|
||||||
|
@apply_blueprint("system/providers-oauth2.yaml")
|
||||||
def test_import_yaml_tags(self):
|
def test_import_yaml_tags(self):
|
||||||
"""Test some yaml tags"""
|
"""Test some yaml tags"""
|
||||||
ExpressionPolicy.objects.filter(name="foo-bar-baz-qux").delete()
|
ExpressionPolicy.objects.filter(name="foo-bar-baz-qux").delete()
|
||||||
@ -136,91 +138,93 @@ class TestBlueprintsV1(TransactionTestCase):
|
|||||||
self.assertTrue(importer.apply())
|
self.assertTrue(importer.apply())
|
||||||
policy = ExpressionPolicy.objects.filter(name="foo-bar-baz-qux").first()
|
policy = ExpressionPolicy.objects.filter(name="foo-bar-baz-qux").first()
|
||||||
self.assertTrue(policy)
|
self.assertTrue(policy)
|
||||||
self.assertTrue(
|
group = Group.objects.filter(name="test").first()
|
||||||
Group.objects.filter(
|
self.assertIsNotNone(group)
|
||||||
attributes={
|
self.assertEqual(
|
||||||
"policy_pk1": str(policy.pk) + "-suffix",
|
group.attributes,
|
||||||
"policy_pk2": str(policy.pk) + "-suffix",
|
{
|
||||||
"boolAnd": True,
|
"policy_pk1": str(policy.pk) + "-suffix",
|
||||||
"boolNand": False,
|
"policy_pk2": str(policy.pk) + "-suffix",
|
||||||
"boolOr": True,
|
"boolAnd": True,
|
||||||
"boolNor": False,
|
"boolNand": False,
|
||||||
"boolXor": True,
|
"boolOr": True,
|
||||||
"boolXnor": False,
|
"boolNor": False,
|
||||||
"boolComplex": True,
|
"boolXor": True,
|
||||||
"if_true_complex": {
|
"boolXnor": False,
|
||||||
"dictionary": {
|
"boolComplex": True,
|
||||||
"with": {"keys": "and_values"},
|
"if_true_complex": {
|
||||||
"and_nested_custom_tags": "foo-bar",
|
"dictionary": {
|
||||||
}
|
"with": {"keys": "and_values"},
|
||||||
|
"and_nested_custom_tags": "foo-bar",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"if_false_complex": ["list", "with", "items", "foo-bar"],
|
||||||
|
"if_true_simple": True,
|
||||||
|
"if_short": True,
|
||||||
|
"if_false_simple": 2,
|
||||||
|
"enumerate_mapping_to_mapping": {
|
||||||
|
"prefix-key1": "other-prefix-value",
|
||||||
|
"prefix-key2": "other-prefix-2",
|
||||||
|
},
|
||||||
|
"enumerate_mapping_to_sequence": [
|
||||||
|
"prefixed-pair-key1-value",
|
||||||
|
"prefixed-pair-key2-2",
|
||||||
|
],
|
||||||
|
"enumerate_sequence_to_sequence": [
|
||||||
|
"prefixed-items-0-foo",
|
||||||
|
"prefixed-items-1-bar",
|
||||||
|
],
|
||||||
|
"enumerate_sequence_to_mapping": {"index: 0": "foo", "index: 1": "bar"},
|
||||||
|
"nested_complex_enumeration": {
|
||||||
|
"0": {
|
||||||
|
"key1": [
|
||||||
|
["prefixed-f", "prefixed-o", "prefixed-o"],
|
||||||
|
{
|
||||||
|
"outer_value": "foo",
|
||||||
|
"outer_index": 0,
|
||||||
|
"middle_value": "value",
|
||||||
|
"middle_index": "key1",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"key2": [
|
||||||
|
["prefixed-f", "prefixed-o", "prefixed-o"],
|
||||||
|
{
|
||||||
|
"outer_value": "foo",
|
||||||
|
"outer_index": 0,
|
||||||
|
"middle_value": 2,
|
||||||
|
"middle_index": "key2",
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
"if_false_complex": ["list", "with", "items", "foo-bar"],
|
"1": {
|
||||||
"if_true_simple": True,
|
"key1": [
|
||||||
"if_short": True,
|
["prefixed-b", "prefixed-a", "prefixed-r"],
|
||||||
"if_false_simple": 2,
|
{
|
||||||
"enumerate_mapping_to_mapping": {
|
"outer_value": "bar",
|
||||||
"prefix-key1": "other-prefix-value",
|
"outer_index": 1,
|
||||||
"prefix-key2": "other-prefix-2",
|
"middle_value": "value",
|
||||||
|
"middle_index": "key1",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"key2": [
|
||||||
|
["prefixed-b", "prefixed-a", "prefixed-r"],
|
||||||
|
{
|
||||||
|
"outer_value": "bar",
|
||||||
|
"outer_index": 1,
|
||||||
|
"middle_value": 2,
|
||||||
|
"middle_index": "key2",
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
"enumerate_mapping_to_sequence": [
|
},
|
||||||
"prefixed-pair-key1-value",
|
"nested_context": "context-nested-value",
|
||||||
"prefixed-pair-key2-2",
|
"env_null": None,
|
||||||
],
|
"at_index_sequence": "foo",
|
||||||
"enumerate_sequence_to_sequence": [
|
"at_index_sequence_default": "non existent",
|
||||||
"prefixed-items-0-foo",
|
"at_index_mapping": 2,
|
||||||
"prefixed-items-1-bar",
|
"at_index_mapping_default": "non existent",
|
||||||
],
|
"find_object": "goauthentik.io/providers/oauth2/scope-openid",
|
||||||
"enumerate_sequence_to_mapping": {"index: 0": "foo", "index: 1": "bar"},
|
},
|
||||||
"nested_complex_enumeration": {
|
|
||||||
"0": {
|
|
||||||
"key1": [
|
|
||||||
["prefixed-f", "prefixed-o", "prefixed-o"],
|
|
||||||
{
|
|
||||||
"outer_value": "foo",
|
|
||||||
"outer_index": 0,
|
|
||||||
"middle_value": "value",
|
|
||||||
"middle_index": "key1",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"key2": [
|
|
||||||
["prefixed-f", "prefixed-o", "prefixed-o"],
|
|
||||||
{
|
|
||||||
"outer_value": "foo",
|
|
||||||
"outer_index": 0,
|
|
||||||
"middle_value": 2,
|
|
||||||
"middle_index": "key2",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"1": {
|
|
||||||
"key1": [
|
|
||||||
["prefixed-b", "prefixed-a", "prefixed-r"],
|
|
||||||
{
|
|
||||||
"outer_value": "bar",
|
|
||||||
"outer_index": 1,
|
|
||||||
"middle_value": "value",
|
|
||||||
"middle_index": "key1",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"key2": [
|
|
||||||
["prefixed-b", "prefixed-a", "prefixed-r"],
|
|
||||||
{
|
|
||||||
"outer_value": "bar",
|
|
||||||
"outer_index": 1,
|
|
||||||
"middle_value": 2,
|
|
||||||
"middle_index": "key2",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"nested_context": "context-nested-value",
|
|
||||||
"env_null": None,
|
|
||||||
"at_index_sequence": "foo",
|
|
||||||
"at_index_sequence_default": "non existent",
|
|
||||||
"at_index_mapping": 2,
|
|
||||||
"at_index_mapping_default": "non existent",
|
|
||||||
}
|
|
||||||
).exists()
|
|
||||||
)
|
)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
OAuthSource.objects.filter(
|
OAuthSource.objects.filter(
|
||||||
|
@ -311,7 +311,7 @@ class Format(YAMLTag):
|
|||||||
|
|
||||||
|
|
||||||
class Find(YAMLTag):
|
class Find(YAMLTag):
|
||||||
"""Find any object"""
|
"""Find any object primary key"""
|
||||||
|
|
||||||
model_name: str | YAMLTag
|
model_name: str | YAMLTag
|
||||||
conditions: list[list]
|
conditions: list[list]
|
||||||
@ -326,7 +326,7 @@ class Find(YAMLTag):
|
|||||||
values.append(loader.construct_object(node_values))
|
values.append(loader.construct_object(node_values))
|
||||||
self.conditions.append(values)
|
self.conditions.append(values)
|
||||||
|
|
||||||
def resolve(self, entry: BlueprintEntry, blueprint: Blueprint) -> Any:
|
def _get_instance(self, entry: BlueprintEntry, blueprint: Blueprint) -> Any:
|
||||||
if isinstance(self.model_name, YAMLTag):
|
if isinstance(self.model_name, YAMLTag):
|
||||||
model_name = self.model_name.resolve(entry, blueprint)
|
model_name = self.model_name.resolve(entry, blueprint)
|
||||||
else:
|
else:
|
||||||
@ -348,12 +348,29 @@ class Find(YAMLTag):
|
|||||||
else:
|
else:
|
||||||
query_value = cond[1]
|
query_value = cond[1]
|
||||||
query &= Q(**{query_key: query_value})
|
query &= Q(**{query_key: query_value})
|
||||||
instance = model_class.objects.filter(query).first()
|
return model_class.objects.filter(query).first()
|
||||||
|
|
||||||
|
def resolve(self, entry: BlueprintEntry, blueprint: Blueprint) -> Any:
|
||||||
|
instance = self._get_instance(entry, blueprint)
|
||||||
if instance:
|
if instance:
|
||||||
return instance.pk
|
return instance.pk
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class FindObject(Find):
|
||||||
|
"""Find any object"""
|
||||||
|
|
||||||
|
def resolve(self, entry: BlueprintEntry, blueprint: Blueprint) -> Any:
|
||||||
|
instance = self._get_instance(entry, blueprint)
|
||||||
|
if not instance:
|
||||||
|
return None
|
||||||
|
if not isinstance(instance, SerializerModel):
|
||||||
|
raise EntryInvalidError.from_entry(
|
||||||
|
f"Model {self.model_name} is not resolvable through FindObject", entry
|
||||||
|
)
|
||||||
|
return instance.serializer(instance=instance).data
|
||||||
|
|
||||||
|
|
||||||
class Condition(YAMLTag):
|
class Condition(YAMLTag):
|
||||||
"""Convert all values to a single boolean"""
|
"""Convert all values to a single boolean"""
|
||||||
|
|
||||||
@ -649,6 +666,7 @@ class BlueprintLoader(SafeLoader):
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.add_constructor("!KeyOf", KeyOf)
|
self.add_constructor("!KeyOf", KeyOf)
|
||||||
self.add_constructor("!Find", Find)
|
self.add_constructor("!Find", Find)
|
||||||
|
self.add_constructor("!FindObject", FindObject)
|
||||||
self.add_constructor("!Context", Context)
|
self.add_constructor("!Context", Context)
|
||||||
self.add_constructor("!Format", Format)
|
self.add_constructor("!Format", Format)
|
||||||
self.add_constructor("!Condition", Condition)
|
self.add_constructor("!Condition", Condition)
|
||||||
|
@ -12,6 +12,7 @@ For VS Code, for example, add these entries to your `settings.json`:
|
|||||||
"!Enumerate sequence",
|
"!Enumerate sequence",
|
||||||
"!Env scalar",
|
"!Env scalar",
|
||||||
"!Find sequence",
|
"!Find sequence",
|
||||||
|
"!FindObject sequence",
|
||||||
"!Format sequence",
|
"!Format sequence",
|
||||||
"!If sequence",
|
"!If sequence",
|
||||||
"!Index scalar",
|
"!Index scalar",
|
||||||
@ -60,7 +61,22 @@ configure_flow:
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
Looks up any model and resolves to the the matches' primary key.
|
Looks up any model and resolves to the matches' primary key.
|
||||||
|
First argument is the model to be queried, remaining arguments are expected to be pairs of key=value pairs to query for.
|
||||||
|
|
||||||
|
#### `!FindObject` <span class="badge badge--version">authentik 2025.2+</span>
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
flow_designation:
|
||||||
|
!AtIndex [
|
||||||
|
!FindObject [authentik_flows.flow, [slug, default-password-change]],
|
||||||
|
designation,
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Looks up any model and resolves to the matches' serialized data.
|
||||||
First argument is the model to be queried, remaining arguments are expected to be pairs of key=value pairs to query for.
|
First argument is the model to be queried, remaining arguments are expected to be pairs of key=value pairs to query for.
|
||||||
|
|
||||||
#### `!Context`
|
#### `!Context`
|
||||||
|
Reference in New Issue
Block a user