open-formulieren / open-forms

Smart and dynamic forms
https://open-forms.readthedocs.io
Other
37 stars 26 forks source link

Als gemeente wil ik als gemachtigde en/of bewindvoerder in de hele keten goed geregistreerd staan #3623

Open joeribekker opened 1 year ago

joeribekker commented 1 year ago

De meeste informatie komt van Vincent maar Rob is de functioneel lead. Ik haak Joeri D aan als liaison naar Rob om de functionaliteiten toe te lichten.

Stappenplan is dan als volgt

  1. ~Inhoudelijk de wijziging bespreken voor OpenFormulieren en OpenZaak (Vincent, Agnesa, Joeri B.)~
  2. ~Proces voor wijziging bespreken irt VNG (Vincent, Agnesa, Joeri B.)~
  3. Inhoudelijke wijziging voorleggen bij Joeri D. (Rotterdam) om te toetsen of Rotterdamse behoefte gedekt is
  4. Verzoek aan Joeri D. en Rob voor testomgeving (Verzoek Den Haag of ook op onze testomgeving mag, tzt bespreken)
  5. Start realisatie
  6. Implementatie op Test omgeving(en)

Open Formulieren

  1. Vanuit de inlog sessie ontvangt OpenFormulieren:

    a. Attributen van de inlogsessie (2 subjecten, verwerken attributen zoals gestuurd vanuit Jeroen de B. (even opnieuw opvragen, want verouderd?)

    b. Machtigingsdiensten (formele naam in stelsel) zijn ook van belang voor vastlegging in de zaak (en dus ook OpenForms doorgeven) omdat hier later in de klantreis in de mijnomgeving hier ook obv wordt opgeroepen. Machtigingsdiensten zijn opgesteld voor:

    • Vrijwillig machtigen – zijn geharmoniseerd tussen Rotterdam en Den Haag. Deze Machtigingsdiensten worden ook “thema’s” of “categorieën” genoemd. Dit is een opdeling van de producten en diensten van de gemeente

    • Machtigingsrol: een Machtigingsdienst gekoppeld aan een rol van voor nu Bewindvoerder (straks ook Curator en mentor)

  2. Prefill binnen de formulier sessie obv de attributen uit de inlog sessie

    a. Generiek verwerken van de inlog sessie (Anoigo onafhankelijk, dus kijken naar generiek DigiD Machtigen koppeling)

    b. Input Agnesa gebruiken voor uitwerking gevraagde prefill in formulier sessie van de gemachtigde en de machtiggever (voor zowel vrijwillig machtigen als Bewind)

Objecten API

Aanpassing object ProductAanvraag. De Objects API kan de attributen vanuit de JWT token (DH-specifiek) als ook de gegevens van de HR koppeling als ook de HaalCentraal BRP koppeling opnemen en doorgeven

Hoe zit dit met Rotterdam?

Open Zaak

Open Zaak kan de attributen vanuit de JWT token (DH specifiek) als ook de gegevens van de HR koppeling als ook de HaalCentraal BRP koppeling opnemen

Hoe zit dit met Rotterdam?

Open Klant

De vastlegging van de Bewindvoerder en client in Open Klant dan wel Klantinteractie API wordt opgepakt in Open Klant. Zie: https://github.com/maykinmedia/open-klant/issues/107

Meta:

Milestones

sergei-maertens commented 10 months ago

One shortcoming right now is that we don't have an option to send the client ID + secret as Basic Auth header, which is required for SIAM.

resolved in master

sergei-maertens commented 10 months ago

Ran into https://github.com/mozilla/mozilla-django-oidc/issues/517 - SIAM responds with a JWT rather than JSON.

Things we can try: pass the Accept: application/json header and see if it responds with JSON instead? it doesn't

sergei-maertens commented 9 months ago

Machtigen test user doesn't seem to be able to actually do machtigen 😬 (logged in with LOA "substantieel")

Image

sergei-maertens commented 9 months ago

Remark from Silvia to think about:

I worry a bit about the out of scope thing of the forms being services. Updating the dienstcatalogus everytime a form is added could be painful

This is not a problem when using a broker since they manage the service catalogue, but it may become a challenge with our django-digid-eherkenning integration.

sergei-maertens commented 8 months ago

This week I explored the impact on a number of applications/standards with Joeri, the summary/notes of this are described here.


Authentication context data model

There is a draft for a data model to capture the authentication context data. This will be formalized and published as a JSON-schema definition. It has been peer reviewed by:

The data model is application/standard-agnostic so that it can be integrated into individual components.

Open Klant

We don't anticipate any impact, the API and relations with a "contactmoment" already allow for registering if an auhorizee (gemachtigde/bewindvoerder/...) was the one contacting the municipality on behalf of the representee.

Information in Open Klant is intended for logging/"read only" access, not to perform permission-related checks in application code. The important aspect is that it can be made clear who exactly had contact and how they can be contacted themselves (phone, e-mail...)

Resources involved: rol, vertegenwoordiger, partij, vertegenwoordiging.

Open Zaak / API's voor Zaakgericht werken

The majority of the authentication context data can already be placed in the Rol resource, especially through:

In this situation, this would mean that the representee is "belanghebbende", with indicatieMachtiging: machtiginggever, while the authorizee would be "initiator" with indicatieMachtiging: gemachtigde. There's an open question in VNG-Realisatie/gemma-zaken#2435 to confirm the correct interpretation of the extra information in RGBZ 2

What is currently unclear, is if it's possible to add multiple Rol'en with duplicate indicatieMachtiging values - this would complicate things for the data-filtering (e.g. when listing zaken in a MijnGemeente portal). The same issue asks for clarification.

What's unclear still is where we can store the mandate metadata, e.g. in which capacity was the authorizee acting (bewindvoerder / mentor / curator / ...) or for which service/service set they were authorized. This will require a new feature in the API standard, but we don't know yet if we have to propose to add this to the Rol resource, or directly attached on the Zaak (awaiting clarification on the previous paragraph first).

Objecten API

Because the authentication context data model will be published as JSON schema, the objecttypes will be able to include a pointer/reference to it for inclusion in an objecttype. This gives each objecttype a straight-forward opt-in for this data only when it's relevant. Not all object types require this information.

Integration in objecttypes/objects API thereby becomes trivial.

Open Formulieren

Storing the authentication context data is straight-forward, as long as we put it in the respective schema down into the registration backends. Adding support for this is "just" development work and can be handled 100% by the OF dev team.

sergei-maertens commented 6 months ago

The following schema describes the authentication context data:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "http://localhost/schema.json",
  "title": "JSON schema definition for authentication context data in Dutch government landscapes",
  "type": "object",
  "oneOf": [
    {"$ref": "#/$defs/digid/schemas/withoutMandate"},
    {"$ref": "#/$defs/digid/schemas/withMandate"},
    {"$ref": "#/$defs/eherkenning/schemas/withoutMandate"},
    {"$ref": "#/$defs/eherkenning/schemas/withMandate"}
  ],
  "$defs": {
    "naturalPerson": {
      "title": "Natural Person",
      "description": "JSON schema to describe a reference to a natural person.",
      "type": "object",
      "required": [
        "identifierType",
        "identifier"
      ],
      "properties": {
        "identifierType": {
          "title": "Identifier type",
          "description": "A natural person is always identified by their BSN (social security number).",
          "const": "bsn"
        },
        "identifier": {
          "title": "Identifier value",
          "description": "BSN which uniquely identifies the authenticated person. Note that the value must follow the format rules for Dutch social security numbers.",
          "type": "string",
          "pattern": "^[0-9]{9}$",
          "format": "nl-bsn"
        }
      },
      "additionalProperties": false
    },

    "company": {
      "title": "Company",
      "description": "A 'company', registered in the Chamber of Commerce (KVK). Can be identified by the COC-number or RSIN.",
      "type": "object",
      "required": [
        "identifierType",
        "identifier"
      ],
      "allOf": [
        {"oneOf": [
          {"$ref": "#/$defs/_company:kvk"},
          {"$ref": "#/$defs/_company:rsin"}
        ]}
      ],
      "properties": {
        "branchNumber": {
          "type": "string",
          "pattern": "^[0-9]{12}$",
          "format": "urn:etoegang:1.9:ServiceRestriction:Vestigingsnr"
        }
      },
      "unevaluatedProperties": false
    },
    "_company:kvk": {
      "title": "Identifying attributes for a company by KVK number",
      "type": "object",
      "required": [
        "identifierType",
        "identifier"
      ],
      "properties": {
        "identifierType": {
          "title": "Identifier type",
          "description": "A company can be identified by its chamber of commerce number.",
          "const": "kvkNummer"
        },
        "identifier": {
          "title": "Identifier value",
          "description": "Chamber of commerce number (KVK-nummer) that uniquely identifies the company.",
          "type": "string",
          "pattern": "^[0-9]{8}$",
          "format": "urn:etoegang:1.9:EntityConcernedID:KvKnr"
        }
      }
    },
    "_company:rsin": {
      "title": "Identifying attributes for a company by RSIN",
      "type": "object",
      "required": [
        "identifierType",
        "identifier"
      ],
      "properties": {
        "identifierType": {
          "title": "Identifier type",
          "description": "A company can be identified by its RSIN.",
          "const": "rsin"
        },
        "identifier": {
          "title": "Identifier value",
          "description": "RSIN that uniquely identifies the legal entity.",
          "type": "string",
          "pattern": "^[0-9]{9}$",
          "format": "urn:etoegang:1.9:EntityConcernedID:RSIN"
        }
      }
    },
    "company:actingSubject": {
      "title": "Person acting for an authenticated company",
      "description": "The actual person who authenticated to represent the given company in their actions.",
      "type": "object",
      "required": [
        "identifierType",
        "identifier"
      ],
      "properties": {
        "identifierType": {
          "description": "The identifier is always some encrypted form, specific to the service provider. I.e. the same physical person gets different identifier values when authenting with different service providers.",
          "const": "opaque"
        },
        "identifier": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },

    "digid": {
      "source": {
        "title": "Means used for authentication",
        "description": "Fixed value to indicate DigiD authentication.",
        "const": "digid"
      },
      "loa": {
        "title": "Level of assurance (betrouwbaarheidsniveaus)",
        "description": "Logius defines the available levels of assurance *and* prescribes what the minimum level must be.",
        "type": "string",
        "enum": [
          "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
          "urn:oasis:names:tc:SAML:2.0:ac:classes:MobileTwoFactorContract",
          "urn:oasis:names:tc:SAML:2.0:ac:classes:Smartcard",
          "urn:oasis:names:tc:SAML:2.0:ac:classes:SmartcardPKI"
        ]
      },
      "service": {
        "title": "A service reference",
        "description": "DigiD mandates are bound to either a single service or serviceSet (a collection of services). A service is identified by its ID.",
        "type": "object",
        "required": ["id"],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          }
        },
        "additionalProperties": false
      },
      "serviceSet": {
        "title": "A set of services (aka theme)",
        "description": "A group of related services for which a mandate can be extended. TODO!",
        "type": "object",
        "required": ["id", "services"],
        "properties": {
          "id": {
            "type": "string"
          },
          "services": {
            "type": "array",
            "minItems": 1,
            "items": {"$ref": "#/$defs/digid/service"}
          }
        },
        "additionalProperties": false
      },
      "schemas": {
        "withoutMandate": {
          "title": "Authentication context data schema for DigiD without mandate",
          "type": "object",
          "required": [
            "source",
            "levelOfAssurance",
            "authorizee"
          ],
          "properties": {
            "source": {"$ref": "#/$defs/digid/source"},
            "levelOfAssurance": {"$ref": "#/$defs/digid/loa"},
            "authorizee": {
              "title": "Authorizee (ge-autoriseerde)",
              "description": "The person who is authorized. Because no mandate is involved, the representee and the authorizee are the same person.",
              "type": "object",
              "required": ["legalSubject"],
              "properties": {
                "legalSubject": {
                  "$ref": "#/$defs/naturalPerson",
                  "title": "Legal subject",
                  "description": "The legal beneficiary of the service(s). Because no mandata is involved, the acting subject and legal subject are the same person."
                }
              },
              "additionalProperties": false
            }
          },
          "additionalProperties": false
        },
        "withMandate": {
          "title": "Authentication context data schema for DigiD with mandate.",
          "description": "DigiD Machtigen (or also known as CombiConnect) is a form of voluntary mandate. A natural person represents another natural person.",
          "type": "object",
          "required": [
            "source",
            "levelOfAssurance",
            "representee",
            "authorizee",
            "mandate"
          ],
          "properties": {
            "source": {"$ref": "#/$defs/digid/source"},
            "levelOfAssurance": {"$ref": "#/$defs/digid/loa"},
            "representee": {"$ref": "#/$defs/naturalPerson"},
            "authorizee": {
              "title": "Authorizee (gemachtigde)",
              "description": "The person who is authorized. Because no mandate is involved, the representee and the authorizee are the same person.",
              "type": "object",
              "required": ["legalSubject"],
              "properties": {
                "legalSubject": {
                  "$ref": "#/$defs/naturalPerson",
                  "title": "Legal subject",
                  "description": "The legal, natural person, mandated to act on behalf of the representee."
                }
              },
              "additionalProperties": false
            },
            "mandate": {
              "title": "Mandate context",
              "description": "Additional context describing the extent of the mandate. At least one dimension/property must be provided.",
              "type": "object",
              "required": [],
              "properties": {
                "services": {
                  "type": "array",
                  "minItems": 1,
                  "items": {"$ref": "#/$defs/digid/service"}
                },
                "serviceSet": {"$ref": "#/$defs/digid/serviceSet"}
              },
              "additionalProperties": false
            }
          },
          "additionalProperties": false
        }
      }
    },

    "eherkenning": {
      "source": {
        "title": "Means used for authentication",
        "description": "Fixed value to indicate eHerkenning authentication.",
        "const": "eherkenning"
      },
      "loa": {
        "title": "Level of assurance (betrouwbaarheidsniveaus)",
        "description": "afsprakenstelsel.etoegang.nl defines the available levels of assurance *and* prescribes what the minimum level must be. Note that a minimum of loa2plus is required these days.",
        "type": "string",
        "enum": [
          "urn:etoegang:core:assurance-class:loa1",
          "urn:etoegang:core:assurance-class:loa2",
          "urn:etoegang:core:assurance-class:loa2plus",
          "urn:etoegang:core:assurance-class:loa3",
          "urn:etoegang:core:assurance-class:loa4"
        ]
      },

      "role": {
        "title": "Role of the mandate, which determines the level of access to services",
        "description": "The role of a mandate, typically assigned through judicial procedures.",
        "type": "string",
        "enum": [
          "bewindvoerder",
          "curator",
          "mentor"
        ]
      },
      "service": {
        "title": "A service reference",
        "description": "Identifying properties of a service present in the service catalog.",
        "type": "object",
        "required": ["id", "uuid"],
        "properties": {
          "id": {
            "type": "string",
            "format": "uri",
            "description": "The ServiceID from the service catalog, for example: 'urn:etoegang:DV:00000001002308836000:services:9113'."
          },
          "uuid": {
            "type": "string",
            "format": "uuid",
            "description": "The ServiceUUID from the service catalog."
          }
        },
        "additionalProperties": false
      },

      "schemas": {
        "withoutMandate": {
          "title": "Authentication context data schema for eHerkenning without mandate",
          "type": "object",
          "required": [
            "source",
            "levelOfAssurance",
            "authorizee"
          ],
          "properties": {
            "source": {"$ref": "#/$defs/eherkenning/source"},
            "levelOfAssurance": {"$ref": "#/$defs/eherkenning/loa"},
            "authorizee": {
              "title": "Authorizee (ge-autoriseerde)",
              "description": "The company that is authorized. Because no mandate is involved, the representee and the authorizee are the same company.",
              "type": "object",
              "required": [
                "legalSubject",
                "actingSubject"
              ],
              "properties": {
                "legalSubject": {
                  "$ref": "#/$defs/company"
                },
                "actingSubject": {
                  "$ref": "#/$defs/company:actingSubject"
                }
              },
              "additionalProperties": false
            }
          },
          "additionalProperties": false
        },
        "withMandate": {
          "title": "Authentication context data schema for eHerkenning without mandate",
          "type": "object",
          "required": [
            "source",
            "levelOfAssurance",
            "representee",
            "authorizee",
            "mandate"
          ],
          "properties": {
            "source": {"$ref": "#/$defs/eherkenning/source"},
            "levelOfAssurance": {"$ref": "#/$defs/eherkenning/loa"},

            "representee": {
              "oneOf": [
                {"$ref": "#/$defs/naturalPerson"},
                {"$ref": "#/$defs/company"}
              ]
            },

            "authorizee": {
              "title": "Authorizee (ge-autoriseerde)",
              "description": "The company that is authorized. Because no mandate is involved, the representee and the authorizee are the same company.",
              "type": "object",
              "required": [
                "legalSubject",
                "actingSubject"
              ],
              "properties": {
                "legalSubject": {
                  "$ref": "#/$defs/company"
                },
                "actingSubject": {
                  "$ref": "#/$defs/company:actingSubject"
                }
              },
              "additionalProperties": false
            },
            "mandate": {
              "title": "Mandate context",
              "description": "Additional context describing the extent of the mandate. At least one dimension/property must be provided.",
              "type": "object",
              "required": [],
              "properties": {
                "services": {
                  "type": "array",
                  "minItems": 1,
                  "items": {"$ref": "#/$defs/eherkenning/service"}
                },
                "role": {"$ref": "#/$defs/eherkenning/role"}
              },
              "additionalProperties": false
            }
          },
          "additionalProperties": false
        }
      }
    }
  }
}

It doesn't yet capture everything, but it should be sufficiently extensible to get to that point.

Next up is actual code changes in Open Forms to capture this data in a sufficiently structured manner.

sergei-maertens commented 4 months ago

Remainder is for 2.8 release cycle, we don't expect further changes in Open Forms.