✨(plugin) add CommuneCreation plugin
Extend plugin mechanism to be able to grant domain admin in Dimail
This commit is contained in:
committed by
Laurent Bossavit
parent
dc938d3159
commit
471f69d4ec
4
Makefile
4
Makefile
@@ -72,6 +72,7 @@ data/static:
|
|||||||
create-env-files: ## Copy the dist env files to env files
|
create-env-files: ## Copy the dist env files to env files
|
||||||
create-env-files: \
|
create-env-files: \
|
||||||
env.d/development/common \
|
env.d/development/common \
|
||||||
|
env.d/development/france \
|
||||||
env.d/development/crowdin \
|
env.d/development/crowdin \
|
||||||
env.d/development/postgresql \
|
env.d/development/postgresql \
|
||||||
env.d/development/kc_postgresql
|
env.d/development/kc_postgresql
|
||||||
@@ -228,6 +229,9 @@ resetdb: ## flush database and create a superuser "admin"
|
|||||||
env.d/development/common:
|
env.d/development/common:
|
||||||
cp -n env.d/development/common.dist env.d/development/common
|
cp -n env.d/development/common.dist env.d/development/common
|
||||||
|
|
||||||
|
env.d/development/france:
|
||||||
|
cp -n env.d/development/france.dist env.d/development/france
|
||||||
|
|
||||||
env.d/development/postgresql:
|
env.d/development/postgresql:
|
||||||
cp -n env.d/development/postgresql.dist env.d/development/postgresql
|
cp -n env.d/development/postgresql.dist env.d/development/postgresql
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ services:
|
|||||||
- DJANGO_CONFIGURATION=Development
|
- DJANGO_CONFIGURATION=Development
|
||||||
env_file:
|
env_file:
|
||||||
- env.d/development/common
|
- env.d/development/common
|
||||||
|
- env.d/development/france
|
||||||
- env.d/development/postgresql
|
- env.d/development/postgresql
|
||||||
ports:
|
ports:
|
||||||
- "8071:8000"
|
- "8071:8000"
|
||||||
|
|||||||
@@ -65,7 +65,7 @@
|
|||||||
"lastName": "Delamairie",
|
"lastName": "Delamairie",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"siret": "21580304000017"
|
"siret": "21510339100011"
|
||||||
},
|
},
|
||||||
"credentials": [
|
"credentials": [
|
||||||
{
|
{
|
||||||
|
|||||||
1
env.d/development/france.dist
Normal file
1
env.d/development/france.dist
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ORGANIZATION_PLUGINS=plugins.organizations.NameFromSiretOrganizationPlugin,plugins.organizations.CommuneCreation
|
||||||
@@ -29,7 +29,10 @@ from timezone_field import TimeZoneField
|
|||||||
from treebeard.mp_tree import MP_Node, MP_NodeManager
|
from treebeard.mp_tree import MP_Node, MP_NodeManager
|
||||||
|
|
||||||
from core.enums import WebhookStatusChoices
|
from core.enums import WebhookStatusChoices
|
||||||
from core.plugins.loader import organization_plugins_run_after_create
|
from core.plugins.loader import (
|
||||||
|
organization_plugins_run_after_create,
|
||||||
|
organization_plugins_run_after_grant_access,
|
||||||
|
)
|
||||||
from core.utils.webhooks import scim_synchronizer
|
from core.utils.webhooks import scim_synchronizer
|
||||||
from core.validators import get_field_validators_from_setting
|
from core.validators import get_field_validators_from_setting
|
||||||
|
|
||||||
@@ -298,6 +301,22 @@ class OrganizationManager(models.Manager):
|
|||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
|
||||||
|
class OrganizationAccessManager(models.Manager):
|
||||||
|
"""
|
||||||
|
Custom manager for the OrganizationAccess model, to manage complexity/automation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def create(self, **kwargs):
|
||||||
|
"""
|
||||||
|
Create an organization access with the given kwargs.
|
||||||
|
|
||||||
|
This method is overridden to call the Organization plugins.
|
||||||
|
"""
|
||||||
|
instance = super().create(**kwargs)
|
||||||
|
organization_plugins_run_after_grant_access(instance)
|
||||||
|
return instance
|
||||||
|
|
||||||
|
|
||||||
class Organization(BaseModel):
|
class Organization(BaseModel):
|
||||||
"""
|
"""
|
||||||
Organization model used to regroup Teams.
|
Organization model used to regroup Teams.
|
||||||
@@ -618,6 +637,8 @@ class OrganizationAccess(BaseModel):
|
|||||||
default=OrganizationRoleChoices.ADMIN,
|
default=OrganizationRoleChoices.ADMIN,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = OrganizationAccessManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = "people_organization_access"
|
db_table = "people_organization_access"
|
||||||
verbose_name = _("Organization/user relation")
|
verbose_name = _("Organization/user relation")
|
||||||
@@ -979,3 +1000,7 @@ class Invitation(BaseModel):
|
|||||||
|
|
||||||
except smtplib.SMTPException as exception:
|
except smtplib.SMTPException as exception:
|
||||||
logger.error("invitation to %s was not sent: %s", self.email, exception)
|
logger.error("invitation to %s was not sent: %s", self.email, exception)
|
||||||
|
|
||||||
|
|
||||||
|
# It's not clear yet how best to split this file.
|
||||||
|
# pylint: disable=C0302
|
||||||
|
|||||||
@@ -11,3 +11,9 @@ class BaseOrganizationPlugin:
|
|||||||
def run_after_create(self, organization) -> None:
|
def run_after_create(self, organization) -> None:
|
||||||
"""Method called after creating an organization."""
|
"""Method called after creating an organization."""
|
||||||
raise NotImplementedError("Plugins must implement the run_after_create method")
|
raise NotImplementedError("Plugins must implement the run_after_create method")
|
||||||
|
|
||||||
|
def run_after_grant_access(self, organization_access) -> None:
|
||||||
|
"""Method called after creating an organization."""
|
||||||
|
raise NotImplementedError(
|
||||||
|
"Plugins must implement the run_after_grant_access method"
|
||||||
|
)
|
||||||
|
|||||||
@@ -30,3 +30,15 @@ def organization_plugins_run_after_create(organization):
|
|||||||
"""
|
"""
|
||||||
for plugin_instance in get_organization_plugins():
|
for plugin_instance in get_organization_plugins():
|
||||||
plugin_instance.run_after_create(organization)
|
plugin_instance.run_after_create(organization)
|
||||||
|
|
||||||
|
|
||||||
|
def organization_plugins_run_after_grant_access(organization_access):
|
||||||
|
"""
|
||||||
|
Run the after grant access method for all organization plugins.
|
||||||
|
|
||||||
|
Each plugin will be called in the order they are listed in the settings.
|
||||||
|
Each plugin is responsible to save changes if needed, this is not optimized
|
||||||
|
but this could be easily improved later if needed.
|
||||||
|
"""
|
||||||
|
for plugin_instance in get_organization_plugins():
|
||||||
|
plugin_instance.run_after_grant_access(organization_access)
|
||||||
|
|||||||
@@ -657,8 +657,6 @@ class Development(Base):
|
|||||||
|
|
||||||
OIDC_ORGANIZATION_REGISTRATION_ID_FIELD = "siret"
|
OIDC_ORGANIZATION_REGISTRATION_ID_FIELD = "siret"
|
||||||
|
|
||||||
ORGANIZATION_PLUGINS = ["plugins.organizations.NameFromSiretOrganizationPlugin"]
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""In dev, force installs needed for Swagger API."""
|
"""In dev, force installs needed for Swagger API."""
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
@@ -706,8 +704,6 @@ class Test(Base):
|
|||||||
|
|
||||||
OIDC_ORGANIZATION_REGISTRATION_ID_FIELD = "siret"
|
OIDC_ORGANIZATION_REGISTRATION_ID_FIELD = "siret"
|
||||||
|
|
||||||
ORGANIZATION_PLUGINS = ["plugins.organizations.NameFromSiretOrganizationPlugin"]
|
|
||||||
|
|
||||||
ORGANIZATION_REGISTRATION_ID_VALIDATORS = [
|
ORGANIZATION_REGISTRATION_ID_VALIDATORS = [
|
||||||
{
|
{
|
||||||
"NAME": "django.core.validators.RegexValidator",
|
"NAME": "django.core.validators.RegexValidator",
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ from requests.adapters import HTTPAdapter, Retry
|
|||||||
|
|
||||||
from core.plugins.base import BaseOrganizationPlugin
|
from core.plugins.base import BaseOrganizationPlugin
|
||||||
|
|
||||||
|
from mailbox_manager.enums import MailDomainRoleChoices
|
||||||
|
from mailbox_manager.models import MailDomain, MailDomainAccess
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -73,8 +76,9 @@ class NameFromSiretOrganizationPlugin(BaseOrganizationPlugin):
|
|||||||
organization.save(update_fields=["name", "updated_at"])
|
organization.save(update_fields=["name", "updated_at"])
|
||||||
logger.info("Organization %s name updated to %s", organization, name)
|
logger.info("Organization %s name updated to %s", organization, name)
|
||||||
|
|
||||||
def run_after_grant_access(self, organization):
|
def run_after_grant_access(self, organization_access):
|
||||||
pass
|
"""After granting an organization access, we don't need to do anything."""
|
||||||
|
|
||||||
|
|
||||||
class ApiCall:
|
class ApiCall:
|
||||||
"""Encapsulates a call to an external API"""
|
"""Encapsulates a call to an external API"""
|
||||||
@@ -85,18 +89,34 @@ class ApiCall:
|
|||||||
url: str = ""
|
url: str = ""
|
||||||
params: dict = {}
|
params: dict = {}
|
||||||
headers: dict = {}
|
headers: dict = {}
|
||||||
response = None
|
response_data = None
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
"""Call the specified API endpoint with supplied parameters and record response"""
|
"""Call the specified API endpoint with supplied parameters and record response"""
|
||||||
if self.method == "POST":
|
if self.method in ("POST", "PATCH"):
|
||||||
self.response = requests.request(
|
response = requests.request(
|
||||||
method=self.method,
|
method=self.method,
|
||||||
url=f"{self.base}/{self.url}",
|
url=f"{self.base}/{self.url}",
|
||||||
json=self.params,
|
json=self.params,
|
||||||
headers=self.headers,
|
headers=self.headers,
|
||||||
timeout=5,
|
timeout=5,
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
response = requests.request(
|
||||||
|
method=self.method,
|
||||||
|
url=f"{self.base}/{self.url}",
|
||||||
|
params=self.params,
|
||||||
|
headers=self.headers,
|
||||||
|
timeout=5,
|
||||||
|
)
|
||||||
|
self.response_data = response.json()
|
||||||
|
logger.info(
|
||||||
|
"API call: %s %s %s %s",
|
||||||
|
self.method,
|
||||||
|
self.url,
|
||||||
|
self.params,
|
||||||
|
self.response_data,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CommuneCreation(BaseOrganizationPlugin):
|
class CommuneCreation(BaseOrganizationPlugin):
|
||||||
@@ -111,25 +131,31 @@ class CommuneCreation(BaseOrganizationPlugin):
|
|||||||
for result in data["results"]:
|
for result in data["results"]:
|
||||||
nature = "nature_juridique"
|
nature = "nature_juridique"
|
||||||
commune = nature in result and result[nature] == "7210"
|
commune = nature in result and result[nature] == "7210"
|
||||||
for organization in result["matching_etablissements"]:
|
if commune:
|
||||||
if organization.get("siret") == siret:
|
return result["siege"]["libelle_commune"].title()
|
||||||
if commune:
|
|
||||||
return organization["libelle_commune"].title()
|
|
||||||
|
|
||||||
logger.warning("No organization name found for SIRET %s", siret)
|
logger.warning("Not a commune: SIRET %s", siret)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def dns_call(self, spec):
|
def dns_call(self, spec):
|
||||||
"""Call to add a DNS record"""
|
"""Call to add a DNS record"""
|
||||||
records = [
|
records = [
|
||||||
{"name": item["target"], "type": item["type"], "data": item["value"]}
|
{
|
||||||
for item in spec.response
|
"name": item["target"],
|
||||||
|
"type": item["type"].upper(),
|
||||||
|
"data": item["value"],
|
||||||
|
"ttl": 3600,
|
||||||
|
}
|
||||||
|
for item in spec.response_data
|
||||||
]
|
]
|
||||||
result = ApiCall()
|
result = ApiCall()
|
||||||
result.method = "PATCH"
|
result.method = "PATCH"
|
||||||
result.base = "https://api.scaleway.com"
|
result.base = "https://api.scaleway.com"
|
||||||
result.url = f"/domain/v2beta1/dns-zones/{spec.inputs["name"]}.collectivite.fr/records"
|
result.url = (
|
||||||
|
f"/domain/v2beta1/dns-zones/{spec.inputs['name']}.collectivite.fr/records"
|
||||||
|
)
|
||||||
result.params = {"changes": [{"add": {"records": records}}]}
|
result.params = {"changes": [{"add": {"records": records}}]}
|
||||||
|
result.headers = {"X-Auth-Token": settings.DNS_PROVISIONING_API_CREDENTIALS}
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def complete_commune_creation(self, name: str) -> ApiCall:
|
def complete_commune_creation(self, name: str) -> ApiCall:
|
||||||
@@ -160,7 +186,7 @@ class CommuneCreation(BaseOrganizationPlugin):
|
|||||||
"context_name": f"{inputs['name']}.collectivite.fr",
|
"context_name": f"{inputs['name']}.collectivite.fr",
|
||||||
}
|
}
|
||||||
create_domain.headers = {
|
create_domain.headers = {
|
||||||
"Authorization": f"Basic: {settings.MAIL_PROVISIONING_API_CREDENTIALS}"
|
"Authorization": f"Basic {settings.MAIL_PROVISIONING_API_CREDENTIALS}"
|
||||||
}
|
}
|
||||||
|
|
||||||
spec_domain = ApiCall()
|
spec_domain = ApiCall()
|
||||||
@@ -168,7 +194,7 @@ class CommuneCreation(BaseOrganizationPlugin):
|
|||||||
spec_domain.base = settings.MAIL_PROVISIONING_API_URL
|
spec_domain.base = settings.MAIL_PROVISIONING_API_URL
|
||||||
spec_domain.url = f"/domains/{inputs['name']}.collectivite.fr/spec"
|
spec_domain.url = f"/domains/{inputs['name']}.collectivite.fr/spec"
|
||||||
spec_domain.headers = {
|
spec_domain.headers = {
|
||||||
"Authorization": f"Basic: {settings.MAIL_PROVISIONING_API_CREDENTIALS}"
|
"Authorization": f"Basic {settings.MAIL_PROVISIONING_API_CREDENTIALS}"
|
||||||
}
|
}
|
||||||
|
|
||||||
return [create_zone, create_domain, spec_domain]
|
return [create_zone, create_domain, spec_domain]
|
||||||
@@ -179,12 +205,13 @@ class CommuneCreation(BaseOrganizationPlugin):
|
|||||||
|
|
||||||
def run_after_create(self, organization):
|
def run_after_create(self, organization):
|
||||||
"""After creating an organization, update the organization name."""
|
"""After creating an organization, update the organization name."""
|
||||||
|
logger.info("In CommuneCreation")
|
||||||
if not organization.registration_id_list:
|
if not organization.registration_id_list:
|
||||||
# No registration ID to convert...
|
# No registration ID to convert...
|
||||||
return
|
return
|
||||||
|
|
||||||
# In the nominal case, there is only one registration ID because
|
# In the nominal case, there is only one registration ID because
|
||||||
# the organization as been created from it.
|
# the organization has been created from it.
|
||||||
try:
|
try:
|
||||||
# Retry logic as the API may be rate limited
|
# Retry logic as the API may be rate limited
|
||||||
s = requests.Session()
|
s = requests.Session()
|
||||||
@@ -196,6 +223,7 @@ class CommuneCreation(BaseOrganizationPlugin):
|
|||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
data = response.json()
|
data = response.json()
|
||||||
name = self.get_organization_name_from_results(data, siret)
|
name = self.get_organization_name_from_results(data, siret)
|
||||||
|
# Not a commune ?
|
||||||
if not name:
|
if not name:
|
||||||
return
|
return
|
||||||
except requests.RequestException as exc:
|
except requests.RequestException as exc:
|
||||||
@@ -206,5 +234,39 @@ class CommuneCreation(BaseOrganizationPlugin):
|
|||||||
organization.save(update_fields=["name", "updated_at"])
|
organization.save(update_fields=["name", "updated_at"])
|
||||||
logger.info("Organization %s name updated to %s", organization, name)
|
logger.info("Organization %s name updated to %s", organization, name)
|
||||||
|
|
||||||
def run_after_grant_access(self, organization):
|
MailDomain.objects.get_or_create(name=f"{name.lower()}.collectivite.fr")
|
||||||
pass
|
|
||||||
|
# Compute and execute the rest of the process
|
||||||
|
tasks = self.complete_commune_creation(name)
|
||||||
|
for task in tasks:
|
||||||
|
task.execute()
|
||||||
|
last_task = self.complete_zone_creation(tasks[-1])
|
||||||
|
last_task.execute()
|
||||||
|
|
||||||
|
def run_after_grant_access(self, organization_access):
|
||||||
|
"""After granting an organization access, check for needed domain access grant."""
|
||||||
|
orga = organization_access.organization
|
||||||
|
user = organization_access.user
|
||||||
|
zone_name = orga.name.lower() + ".collectivite.fr"
|
||||||
|
|
||||||
|
try:
|
||||||
|
domain = MailDomain.objects.get(domain=zone_name)
|
||||||
|
except MailDomain.DoesNotExist:
|
||||||
|
domain = None
|
||||||
|
|
||||||
|
if domain:
|
||||||
|
MailDomainAccess.objects.create(
|
||||||
|
domain=domain, user=user, role=MailDomainRoleChoices.OWNER
|
||||||
|
)
|
||||||
|
grant_access = ApiCall()
|
||||||
|
grant_access.method = "POST"
|
||||||
|
grant_access.base = settings.MAIL_PROVISIONING_API_URL
|
||||||
|
grant_access.url = "/allows"
|
||||||
|
grant_access.params = {
|
||||||
|
"user": user.sub,
|
||||||
|
"domain": zone_name,
|
||||||
|
}
|
||||||
|
grant_access.headers = {
|
||||||
|
"Authorization": f"Basic {settings.MAIL_PROVISIONING_API_CREDENTIALS}"
|
||||||
|
}
|
||||||
|
grant_access.execute()
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ def test_tasks_on_commune_creation_include_dimail_domain_creation():
|
|||||||
}
|
}
|
||||||
assert (
|
assert (
|
||||||
tasks[1].headers["Authorization"]
|
tasks[1].headers["Authorization"]
|
||||||
== f"Basic: {settings.MAIL_PROVISIONING_API_CREDENTIALS}"
|
== f"Basic {settings.MAIL_PROVISIONING_API_CREDENTIALS}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ def test_tasks_on_commune_creation_include_fetching_spec():
|
|||||||
assert tasks[2].method == "GET"
|
assert tasks[2].method == "GET"
|
||||||
assert (
|
assert (
|
||||||
tasks[2].headers["Authorization"]
|
tasks[2].headers["Authorization"]
|
||||||
== f"Basic: {settings.MAIL_PROVISIONING_API_CREDENTIALS}"
|
== f"Basic {settings.MAIL_PROVISIONING_API_CREDENTIALS}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -143,7 +143,7 @@ def test_tasks_on_commune_creation_include_dns_records():
|
|||||||
]
|
]
|
||||||
|
|
||||||
tasks = plugin.complete_commune_creation(name)
|
tasks = plugin.complete_commune_creation(name)
|
||||||
tasks[2].response = spec_response
|
tasks[2].response_data = spec_response
|
||||||
|
|
||||||
expected = {
|
expected = {
|
||||||
"changes": [
|
"changes": [
|
||||||
@@ -152,8 +152,9 @@ def test_tasks_on_commune_creation_include_dns_records():
|
|||||||
"records": [
|
"records": [
|
||||||
{
|
{
|
||||||
"name": item["target"],
|
"name": item["target"],
|
||||||
"type": item["type"],
|
"type": item["type"].upper(),
|
||||||
"data": item["value"],
|
"data": item["value"],
|
||||||
|
"ttl": 3600,
|
||||||
}
|
}
|
||||||
for item in spec_response
|
for item in spec_response
|
||||||
]
|
]
|
||||||
@@ -165,3 +166,6 @@ def test_tasks_on_commune_creation_include_dns_records():
|
|||||||
zone_call = plugin.complete_zone_creation(tasks[2])
|
zone_call = plugin.complete_zone_creation(tasks[2])
|
||||||
assert zone_call.params == expected
|
assert zone_call.params == expected
|
||||||
assert zone_call.url == "/domain/v2beta1/dns-zones/abidos.collectivite.fr/records"
|
assert zone_call.url == "/domain/v2beta1/dns-zones/abidos.collectivite.fr/records"
|
||||||
|
assert (
|
||||||
|
zone_call.headers["X-Auth-Token"] == settings.DNS_PROVISIONING_API_CREDENTIALS
|
||||||
|
)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ test.describe('OIDC interop with SIRET', () => {
|
|||||||
);
|
);
|
||||||
expect(response.ok()).toBeTruthy();
|
expect(response.ok()).toBeTruthy();
|
||||||
expect(await response.json()).toMatchObject({
|
expect(await response.json()).toMatchObject({
|
||||||
organization: { registration_id_list: ['21580304000017'] },
|
organization: { registration_id_list: ['21510339100011'] },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -28,6 +28,6 @@ test.describe('When a commune, display commune name below user name', () => {
|
|||||||
name: 'Marie Delamairie',
|
name: 'Marie Delamairie',
|
||||||
});
|
});
|
||||||
|
|
||||||
await expect(logout.getByText('Varzy')).toBeVisible();
|
await expect(logout.getByText('Merlaut')).toBeVisible();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ backend:
|
|||||||
OIDC_RP_SCOPES: "openid email siret"
|
OIDC_RP_SCOPES: "openid email siret"
|
||||||
OIDC_REDIRECT_ALLOWED_HOSTS: https://desk.127.0.0.1.nip.io
|
OIDC_REDIRECT_ALLOWED_HOSTS: https://desk.127.0.0.1.nip.io
|
||||||
OIDC_AUTH_REQUEST_EXTRA_PARAMS: "{'acr_values': 'eidas1'}"
|
OIDC_AUTH_REQUEST_EXTRA_PARAMS: "{'acr_values': 'eidas1'}"
|
||||||
ORGANIZATION_PLUGINS: "plugins.organizations.NameFromSiretOrganizationPlugin"
|
|
||||||
ORGANIZATION_REGISTRATION_ID_VALIDATORS: '[{"NAME": "django.core.validators.RegexValidator", "OPTIONS": {"regex": "^[0-9]{14}$"}}]'
|
ORGANIZATION_REGISTRATION_ID_VALIDATORS: '[{"NAME": "django.core.validators.RegexValidator", "OPTIONS": {"regex": "^[0-9]{14}$"}}]'
|
||||||
LOGIN_REDIRECT_URL: https://desk.127.0.0.1.nip.io
|
LOGIN_REDIRECT_URL: https://desk.127.0.0.1.nip.io
|
||||||
LOGIN_REDIRECT_URL_FAILURE: https://desk.127.0.0.1.nip.io
|
LOGIN_REDIRECT_URL_FAILURE: https://desk.127.0.0.1.nip.io
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ backend:
|
|||||||
USER_OIDC_FIELDS_TO_NAME: "given_name,usual_name"
|
USER_OIDC_FIELDS_TO_NAME: "given_name,usual_name"
|
||||||
OIDC_REDIRECT_ALLOWED_HOSTS: https://desk.127.0.0.1.nip.io
|
OIDC_REDIRECT_ALLOWED_HOSTS: https://desk.127.0.0.1.nip.io
|
||||||
OIDC_AUTH_REQUEST_EXTRA_PARAMS: "{'acr_values': 'eidas1'}"
|
OIDC_AUTH_REQUEST_EXTRA_PARAMS: "{'acr_values': 'eidas1'}"
|
||||||
ORGANIZATION_PLUGINS: "plugins.organizations.NameFromSiretOrganizationPlugin"
|
|
||||||
ORGANIZATION_REGISTRATION_ID_VALIDATORS: '[{"NAME": "django.core.validators.RegexValidator", "OPTIONS": {"regex": "^[0-9]{14}$"}}]'
|
ORGANIZATION_REGISTRATION_ID_VALIDATORS: '[{"NAME": "django.core.validators.RegexValidator", "OPTIONS": {"regex": "^[0-9]{14}$"}}]'
|
||||||
LOGIN_REDIRECT_URL: https://desk.127.0.0.1.nip.io
|
LOGIN_REDIRECT_URL: https://desk.127.0.0.1.nip.io
|
||||||
LOGIN_REDIRECT_URL_FAILURE: https://desk.127.0.0.1.nip.io
|
LOGIN_REDIRECT_URL_FAILURE: https://desk.127.0.0.1.nip.io
|
||||||
|
|||||||
Reference in New Issue
Block a user