authentik.blueprints.v1.exporter
Blueprint exporter
1"""Blueprint exporter""" 2 3from collections.abc import Iterable 4from uuid import UUID 5 6from django.apps import apps 7from django.contrib.auth import get_user_model 8from django.db.models import Model, Q, QuerySet 9from django.utils.timezone import now 10from django.utils.translation import gettext as _ 11from yaml import dump 12 13from authentik.blueprints.v1.common import ( 14 Blueprint, 15 BlueprintDumper, 16 BlueprintEntry, 17 BlueprintMetadata, 18) 19from authentik.blueprints.v1.importer import is_model_allowed 20from authentik.blueprints.v1.labels import LABEL_AUTHENTIK_GENERATED 21from authentik.events.models import Event 22from authentik.flows.models import Flow, FlowStageBinding, Stage 23from authentik.policies.models import Policy, PolicyBinding 24from authentik.stages.prompt.models import PromptStage 25 26 27class Exporter: 28 """Export flow with attached stages into yaml""" 29 30 excluded_models: list[type[Model]] = [] 31 32 def __init__(self): 33 self.excluded_models = [ 34 Event, 35 ] 36 37 def get_entries(self) -> Iterable[BlueprintEntry]: 38 """Get blueprint entries""" 39 for model in apps.get_models(): 40 if not is_model_allowed(model): 41 continue 42 if model in self.excluded_models: 43 continue 44 for obj in self.get_model_instances(model): 45 yield BlueprintEntry.from_model(obj) 46 47 def get_model_instances(self, model: type[Model]) -> QuerySet: 48 """Return a queryset for `model`. Can be used to filter some 49 objects on some models""" 50 if model == get_user_model(): 51 return model.objects.exclude_anonymous() 52 return model.objects.all() 53 54 def _pre_export(self, blueprint: Blueprint): 55 """Hook to run anything pre-export""" 56 57 def export(self) -> Blueprint: 58 """Create a list of all objects and create a blueprint""" 59 blueprint = Blueprint() 60 self._pre_export(blueprint) 61 blueprint.metadata = BlueprintMetadata( 62 name=_("authentik Export - {date}".format_map({"date": str(now())})), 63 labels={ 64 LABEL_AUTHENTIK_GENERATED: "true", 65 }, 66 ) 67 blueprint.entries = list(self.get_entries()) 68 return blueprint 69 70 def export_to_string(self) -> str: 71 """Call export and convert it to yaml""" 72 blueprint = self.export() 73 return dump(blueprint, Dumper=BlueprintDumper) 74 75 76class FlowExporter(Exporter): 77 """Exporter customized to only return objects related to `flow`""" 78 79 flow: Flow 80 with_policies: bool 81 with_stage_prompts: bool 82 83 pbm_uuids: list[UUID] 84 85 def __init__(self, flow: Flow): 86 super().__init__() 87 self.flow = flow 88 self.with_policies = True 89 self.with_stage_prompts = True 90 91 def _pre_export(self, blueprint: Blueprint): 92 if not self.with_policies: 93 return 94 self.pbm_uuids = [self.flow.pbm_uuid] 95 self.pbm_uuids += FlowStageBinding.objects.filter(target=self.flow).values_list( 96 "pbm_uuid", flat=True 97 ) 98 99 def walk_stages(self) -> Iterable[BlueprintEntry]: 100 """Convert all stages attached to self.flow into BlueprintEntry objects""" 101 stages = Stage.objects.filter(flow=self.flow).select_related().select_subclasses() 102 for stage in stages: 103 if isinstance(stage, PromptStage): 104 pass 105 yield BlueprintEntry.from_model(stage, "name") 106 107 def walk_stage_bindings(self) -> Iterable[BlueprintEntry]: 108 """Convert all bindings attached to self.flow into BlueprintEntry objects""" 109 bindings = FlowStageBinding.objects.filter(target=self.flow).select_related() 110 for binding in bindings: 111 yield BlueprintEntry.from_model(binding, "target", "stage", "order") 112 113 def walk_policies(self) -> Iterable[BlueprintEntry]: 114 """Walk over all policies. This is done at the beginning of the export for stages that have 115 a direct foreign key to a policy.""" 116 # Special case for PromptStage as that has a direct M2M to policy, we have to ensure 117 # all policies referenced in there we also include here 118 prompt_stages = PromptStage.objects.filter(flow=self.flow).values_list("pk", flat=True) 119 query = Q(bindings__in=self.pbm_uuids) | Q(promptstage__in=prompt_stages) 120 policies = Policy.objects.filter(query).select_related() 121 for policy in policies: 122 yield BlueprintEntry.from_model(policy) 123 124 def walk_policy_bindings(self) -> Iterable[BlueprintEntry]: 125 """Walk over all policybindings relative to us. This is run at the end of the export, as 126 we are sure all objects exist now.""" 127 bindings = PolicyBinding.objects.filter(target__in=self.pbm_uuids).select_related() 128 for binding in bindings: 129 yield BlueprintEntry.from_model(binding, "policy", "target", "order") 130 131 def walk_stage_prompts(self) -> Iterable[BlueprintEntry]: 132 """Walk over all prompts associated with any PromptStages""" 133 prompt_stages = PromptStage.objects.filter(flow=self.flow) 134 for stage in prompt_stages: 135 for prompt in stage.fields.all(): 136 yield BlueprintEntry.from_model(prompt) 137 138 def get_entries(self) -> Iterable[BlueprintEntry]: 139 entries = [] 140 entries.append(BlueprintEntry.from_model(self.flow, "slug")) 141 if self.with_stage_prompts: 142 entries.extend(self.walk_stage_prompts()) 143 if self.with_policies: 144 entries.extend(self.walk_policies()) 145 entries.extend(self.walk_stages()) 146 entries.extend(self.walk_stage_bindings()) 147 if self.with_policies: 148 entries.extend(self.walk_policy_bindings()) 149 return entries
class
Exporter:
28class Exporter: 29 """Export flow with attached stages into yaml""" 30 31 excluded_models: list[type[Model]] = [] 32 33 def __init__(self): 34 self.excluded_models = [ 35 Event, 36 ] 37 38 def get_entries(self) -> Iterable[BlueprintEntry]: 39 """Get blueprint entries""" 40 for model in apps.get_models(): 41 if not is_model_allowed(model): 42 continue 43 if model in self.excluded_models: 44 continue 45 for obj in self.get_model_instances(model): 46 yield BlueprintEntry.from_model(obj) 47 48 def get_model_instances(self, model: type[Model]) -> QuerySet: 49 """Return a queryset for `model`. Can be used to filter some 50 objects on some models""" 51 if model == get_user_model(): 52 return model.objects.exclude_anonymous() 53 return model.objects.all() 54 55 def _pre_export(self, blueprint: Blueprint): 56 """Hook to run anything pre-export""" 57 58 def export(self) -> Blueprint: 59 """Create a list of all objects and create a blueprint""" 60 blueprint = Blueprint() 61 self._pre_export(blueprint) 62 blueprint.metadata = BlueprintMetadata( 63 name=_("authentik Export - {date}".format_map({"date": str(now())})), 64 labels={ 65 LABEL_AUTHENTIK_GENERATED: "true", 66 }, 67 ) 68 blueprint.entries = list(self.get_entries()) 69 return blueprint 70 71 def export_to_string(self) -> str: 72 """Call export and convert it to yaml""" 73 blueprint = self.export() 74 return dump(blueprint, Dumper=BlueprintDumper)
Export flow with attached stages into yaml
38 def get_entries(self) -> Iterable[BlueprintEntry]: 39 """Get blueprint entries""" 40 for model in apps.get_models(): 41 if not is_model_allowed(model): 42 continue 43 if model in self.excluded_models: 44 continue 45 for obj in self.get_model_instances(model): 46 yield BlueprintEntry.from_model(obj)
Get blueprint entries
def
get_model_instances( self, model: type[django.db.models.base.Model]) -> django.db.models.query.QuerySet:
48 def get_model_instances(self, model: type[Model]) -> QuerySet: 49 """Return a queryset for `model`. Can be used to filter some 50 objects on some models""" 51 if model == get_user_model(): 52 return model.objects.exclude_anonymous() 53 return model.objects.all()
Return a queryset for model. Can be used to filter some
objects on some models
58 def export(self) -> Blueprint: 59 """Create a list of all objects and create a blueprint""" 60 blueprint = Blueprint() 61 self._pre_export(blueprint) 62 blueprint.metadata = BlueprintMetadata( 63 name=_("authentik Export - {date}".format_map({"date": str(now())})), 64 labels={ 65 LABEL_AUTHENTIK_GENERATED: "true", 66 }, 67 ) 68 blueprint.entries = list(self.get_entries()) 69 return blueprint
Create a list of all objects and create a blueprint
77class FlowExporter(Exporter): 78 """Exporter customized to only return objects related to `flow`""" 79 80 flow: Flow 81 with_policies: bool 82 with_stage_prompts: bool 83 84 pbm_uuids: list[UUID] 85 86 def __init__(self, flow: Flow): 87 super().__init__() 88 self.flow = flow 89 self.with_policies = True 90 self.with_stage_prompts = True 91 92 def _pre_export(self, blueprint: Blueprint): 93 if not self.with_policies: 94 return 95 self.pbm_uuids = [self.flow.pbm_uuid] 96 self.pbm_uuids += FlowStageBinding.objects.filter(target=self.flow).values_list( 97 "pbm_uuid", flat=True 98 ) 99 100 def walk_stages(self) -> Iterable[BlueprintEntry]: 101 """Convert all stages attached to self.flow into BlueprintEntry objects""" 102 stages = Stage.objects.filter(flow=self.flow).select_related().select_subclasses() 103 for stage in stages: 104 if isinstance(stage, PromptStage): 105 pass 106 yield BlueprintEntry.from_model(stage, "name") 107 108 def walk_stage_bindings(self) -> Iterable[BlueprintEntry]: 109 """Convert all bindings attached to self.flow into BlueprintEntry objects""" 110 bindings = FlowStageBinding.objects.filter(target=self.flow).select_related() 111 for binding in bindings: 112 yield BlueprintEntry.from_model(binding, "target", "stage", "order") 113 114 def walk_policies(self) -> Iterable[BlueprintEntry]: 115 """Walk over all policies. This is done at the beginning of the export for stages that have 116 a direct foreign key to a policy.""" 117 # Special case for PromptStage as that has a direct M2M to policy, we have to ensure 118 # all policies referenced in there we also include here 119 prompt_stages = PromptStage.objects.filter(flow=self.flow).values_list("pk", flat=True) 120 query = Q(bindings__in=self.pbm_uuids) | Q(promptstage__in=prompt_stages) 121 policies = Policy.objects.filter(query).select_related() 122 for policy in policies: 123 yield BlueprintEntry.from_model(policy) 124 125 def walk_policy_bindings(self) -> Iterable[BlueprintEntry]: 126 """Walk over all policybindings relative to us. This is run at the end of the export, as 127 we are sure all objects exist now.""" 128 bindings = PolicyBinding.objects.filter(target__in=self.pbm_uuids).select_related() 129 for binding in bindings: 130 yield BlueprintEntry.from_model(binding, "policy", "target", "order") 131 132 def walk_stage_prompts(self) -> Iterable[BlueprintEntry]: 133 """Walk over all prompts associated with any PromptStages""" 134 prompt_stages = PromptStage.objects.filter(flow=self.flow) 135 for stage in prompt_stages: 136 for prompt in stage.fields.all(): 137 yield BlueprintEntry.from_model(prompt) 138 139 def get_entries(self) -> Iterable[BlueprintEntry]: 140 entries = [] 141 entries.append(BlueprintEntry.from_model(self.flow, "slug")) 142 if self.with_stage_prompts: 143 entries.extend(self.walk_stage_prompts()) 144 if self.with_policies: 145 entries.extend(self.walk_policies()) 146 entries.extend(self.walk_stages()) 147 entries.extend(self.walk_stage_bindings()) 148 if self.with_policies: 149 entries.extend(self.walk_policy_bindings()) 150 return entries
Exporter customized to only return objects related to flow
FlowExporter(flow: authentik.flows.models.Flow)
100 def walk_stages(self) -> Iterable[BlueprintEntry]: 101 """Convert all stages attached to self.flow into BlueprintEntry objects""" 102 stages = Stage.objects.filter(flow=self.flow).select_related().select_subclasses() 103 for stage in stages: 104 if isinstance(stage, PromptStage): 105 pass 106 yield BlueprintEntry.from_model(stage, "name")
Convert all stages attached to self.flow into BlueprintEntry objects
108 def walk_stage_bindings(self) -> Iterable[BlueprintEntry]: 109 """Convert all bindings attached to self.flow into BlueprintEntry objects""" 110 bindings = FlowStageBinding.objects.filter(target=self.flow).select_related() 111 for binding in bindings: 112 yield BlueprintEntry.from_model(binding, "target", "stage", "order")
Convert all bindings attached to self.flow into BlueprintEntry objects
114 def walk_policies(self) -> Iterable[BlueprintEntry]: 115 """Walk over all policies. This is done at the beginning of the export for stages that have 116 a direct foreign key to a policy.""" 117 # Special case for PromptStage as that has a direct M2M to policy, we have to ensure 118 # all policies referenced in there we also include here 119 prompt_stages = PromptStage.objects.filter(flow=self.flow).values_list("pk", flat=True) 120 query = Q(bindings__in=self.pbm_uuids) | Q(promptstage__in=prompt_stages) 121 policies = Policy.objects.filter(query).select_related() 122 for policy in policies: 123 yield BlueprintEntry.from_model(policy)
Walk over all policies. This is done at the beginning of the export for stages that have a direct foreign key to a policy.
125 def walk_policy_bindings(self) -> Iterable[BlueprintEntry]: 126 """Walk over all policybindings relative to us. This is run at the end of the export, as 127 we are sure all objects exist now.""" 128 bindings = PolicyBinding.objects.filter(target__in=self.pbm_uuids).select_related() 129 for binding in bindings: 130 yield BlueprintEntry.from_model(binding, "policy", "target", "order")
Walk over all policybindings relative to us. This is run at the end of the export, as we are sure all objects exist now.
132 def walk_stage_prompts(self) -> Iterable[BlueprintEntry]: 133 """Walk over all prompts associated with any PromptStages""" 134 prompt_stages = PromptStage.objects.filter(flow=self.flow) 135 for stage in prompt_stages: 136 for prompt in stage.fields.all(): 137 yield BlueprintEntry.from_model(prompt)
Walk over all prompts associated with any PromptStages
139 def get_entries(self) -> Iterable[BlueprintEntry]: 140 entries = [] 141 entries.append(BlueprintEntry.from_model(self.flow, "slug")) 142 if self.with_stage_prompts: 143 entries.extend(self.walk_stage_prompts()) 144 if self.with_policies: 145 entries.extend(self.walk_policies()) 146 entries.extend(self.walk_stages()) 147 entries.extend(self.walk_stage_bindings()) 148 if self.with_policies: 149 entries.extend(self.walk_policy_bindings()) 150 return entries
Get blueprint entries