Skip to content

Commit

Permalink
🚧 [#1471] Add DigiD machtigen plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
SilviaAmAm committed Mar 31, 2022
1 parent 55052e0 commit 5e35f25
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import logging
from copy import deepcopy

from glom import PathAccessError, glom

from digid_eherkenning_oidc_generics.backends import OIDCAuthenticationBackend
from digid_eherkenning_oidc_generics.mixins import (
SoloConfigDigiDMixin,
SoloConfigEHerkenningMixin,
)
from digid_eherkenning_oidc_generics.utils import obfuscate_claim

from .constants import DIGID_OIDC_AUTH_SESSION_KEY, EHERKENNING_OIDC_AUTH_SESSION_KEY
from .constants import (
DIGID_MACHTIGEN_OIDC_AUTH_SESSION_KEY,
DIGID_OIDC_AUTH_SESSION_KEY,
EHERKENNING_OIDC_AUTH_SESSION_KEY,
)

logger = logging.getLogger(__name__)

Expand All @@ -27,3 +35,55 @@ class OIDCAuthenticationEHerkenningBackend(
"""

session_key = EHERKENNING_OIDC_AUTH_SESSION_KEY


class OIDCAuthenticationDigiDMachtigenBackend(
SoloConfigDigiDMixin, OIDCAuthenticationBackend
):
session_key = DIGID_MACHTIGEN_OIDC_AUTH_SESSION_KEY

def extract_claims(self, payload: dict) -> None:
claim_names = [
self.config.vertegenwoordigde_claim_name,
self.config.gemachtigde_claim_name,
]

self.request.session[self.session_key] = {}
for claim_name in claim_names:
self.request.session[self.session_key][claim_name] = glom(
payload, claim_name
)

def log_received_claims(self, claims: dict):
copied_claims = deepcopy(claims)

def _obfuscate_claims_values(claims_to_obfuscate: dict) -> dict:
for key, value in claims_to_obfuscate.items():
if isinstance(value, dict):
_obfuscate_claims_values(value)
else:
claims_to_obfuscate[key] = obfuscate_claim(value)
return claims_to_obfuscate

obfuscated_claims = _obfuscate_claims_values(copied_claims)
logger.debug("OIDC claims received: %s", obfuscated_claims)

def verify_claims(self, claims: dict) -> bool:
expected_claim_names = [
self.config.vertegenwoordigde_claim_name,
self.config.gemachtigde_claim_name,
]

self.log_received_claims(claims)

for expected_claim in expected_claim_names:
try:
glom(claims, expected_claim)
except PathAccessError:
logger.error(
"`%s` not in OIDC claims, cannot proceed with DigiD Machtigen authentication",
expected_claim,
)
return False

return True
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
DIGID_OIDC_AUTH_SESSION_KEY = "digid_oidc:bsn"
EHERKENNING_OIDC_AUTH_SESSION_KEY = "eherkenning_oidc:kvk"
DIGID_MACHTIGEN_OIDC_AUTH_SESSION_KEY = "digid_machtigen_oidc:machtigen"
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from django.urls import path

from mozilla_django_oidc.urls import urlpatterns

from .views import (
DigiDMachtigenOIDCAuthenticationCallbackView,
DigiDMachtigenOIDCAuthenticationRequestView,
)

app_name = "digid_machtigen_oidc"


urlpatterns = [
path(
"callback/",
DigiDMachtigenOIDCAuthenticationCallbackView.as_view(),
name="callback",
),
path(
"authenticate/",
DigiDMachtigenOIDCAuthenticationRequestView.as_view(),
name="init",
),
] + urlpatterns
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@
from ...constants import CO_SIGN_PARAMETER, FORM_AUTH_SESSION_KEY, AuthAttribute
from ...exceptions import InvalidCoSignData
from ...registry import register
from .constants import DIGID_OIDC_AUTH_SESSION_KEY, EHERKENNING_OIDC_AUTH_SESSION_KEY
from .constants import (
DIGID_MACHTIGEN_OIDC_AUTH_SESSION_KEY,
DIGID_OIDC_AUTH_SESSION_KEY,
EHERKENNING_OIDC_AUTH_SESSION_KEY,
)


class OIDCAuthentication(BasePlugin):
Expand Down Expand Up @@ -59,6 +63,15 @@ def handle_co_sign(
"fields": {},
}

def add_claims_to_sessions_if_not_cosigning(self, claim, request):
# set the session auth key only if we're not co-signing
if claim and CO_SIGN_PARAMETER not in request.GET:
request.session[FORM_AUTH_SESSION_KEY] = {
"plugin": self.identifier,
"attribute": self.provides_auth,
"value": claim,
}

def handle_return(self, request, form):
"""
Redirect to form URL.
Expand All @@ -69,13 +82,7 @@ def handle_return(self, request, form):

claim = request.session.get(self.session_key)

# set the session auth key only if we're not co-signing
if claim and CO_SIGN_PARAMETER not in request.GET:
request.session[FORM_AUTH_SESSION_KEY] = {
"plugin": self.identifier,
"attribute": self.provides_auth,
"value": claim,
}
self.add_claims_to_sessions_if_not_cosigning(claim, request)

return HttpResponseRedirect(form_url)

Expand Down Expand Up @@ -129,3 +136,23 @@ def get_label(self) -> str:

def get_logo(self, request) -> Optional[LoginLogo]:
return LoginLogo(title=self.get_label(), **get_eherkenning_logo(request))


@register("digid_machtigen_oidc")
class DigiDMachtigenOIDCAuthentication(OIDCAuthentication):
verbose_name = _("DigiD Machtigen via OpenID Connect")
provides_auth = AuthAttribute.bsn
init_url = "digid_machtigen_oidc:init"
session_key = DIGID_MACHTIGEN_OIDC_AUTH_SESSION_KEY
config_class = OpenIDConnectPublicConfig

def add_claims_to_sessions_if_not_cosigning(self, claim, request):
# set the session auth key only if we're not co-signing
if claim and CO_SIGN_PARAMETER not in request.GET:
config = OpenIDConnectPublicConfig.get_solo()
request.session[FORM_AUTH_SESSION_KEY] = {
"plugin": self.identifier,
"attribute": self.provides_auth,
"value": claim[config.vertegenwoordigde_claim_name],
"machtigen": request.session[DIGID_MACHTIGEN_OIDC_AUTH_SESSION_KEY],
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from ...views import BACKEND_OUTAGE_RESPONSE_PARAMETER
from .backends import (
OIDCAuthenticationDigiDBackend,
OIDCAuthenticationDigiDMachtigenBackend,
OIDCAuthenticationEHerkenningBackend,
)

Expand Down Expand Up @@ -92,3 +93,16 @@ class eHerkenningOIDCAuthenticationCallbackView(
):
plugin_identifier = "eherkenning_oidc"
auth_backend_class = OIDCAuthenticationEHerkenningBackend


class DigiDMachtigenOIDCAuthenticationRequestView(
SoloConfigDigiDMixin, OIDCAuthenticationRequestView
):
plugin_identifier = "digid_machtigen_oidc"


class DigiDMachtigenOIDCAuthenticationCallbackView(
SoloConfigDigiDMixin, OIDCAuthenticationCallbackView
):
plugin_identifier = "digid_machtigen_oidc"
auth_backend_class = OIDCAuthenticationDigiDMachtigenBackend
3 changes: 2 additions & 1 deletion src/openforms/authentication/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Literal, TypedDict
from typing import Literal, Optional, TypedDict

from openforms.submissions.models import Submission

Expand All @@ -13,6 +13,7 @@ class FormAuth(TypedDict):
AuthAttribute.pseudo,
]
value: str
machtigen: Optional[dict]


def store_auth_details(submission: Submission, form_auth: FormAuth) -> None:
Expand Down
6 changes: 6 additions & 0 deletions src/openforms/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@
"openforms.authentication.contrib.digid_eherkenning_oidc.eherkenning_urls",
),
),
path(
"digid-machtigen-oidc/",
include(
"openforms.authentication.contrib.digid_eherkenning_oidc.digid_machtigen_urls",
),
),
path("payment/", include("openforms.payments.urls", namespace="payments")),
# NOTE: we dont use the User creation feature so don't enable all the mock views
path("digid/", include("openforms.authentication.contrib.digid.urls")),
Expand Down

0 comments on commit 5e35f25

Please sign in to comment.