Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

App-user/token(s) for background processing, cleanup, service tasks #813

Open
martinothamar opened this issue Oct 4, 2024 · 0 comments
Open
Assignees

Comments

@martinothamar
Copy link
Contributor

martinothamar commented Oct 4, 2024

Description

For a long time we've anticipated the need for making requests not in the context of a user, but in the context of the app itself. This issue will detail why and when/where we need it from the current state of the library and to support future work around the process engine

In scope

  • Mechanisms to support authorization against other services inside and outside Altinn 3 without a users token

Out of scope

No response

Additional Information

In a meeting with members from Core and Authorization, we landed on 2 possible solutions that we need to investigate.

  • Idea 1
    • Authorization/Authentication has an endpoint for creating an app-specific token
    • The token is contextualized with instance ID and possibly other claims (e.g. to make it possible to implement something like CausedBy in InstanceEvents in Storage)
    • Issued as a normal Altinn token
    • Would require XACML policy changes and would therefore require a major bump for app-lib
      • Unless a special case fallback policy is implemented in Authorization
      • Or Studio changes the policy upon deploy
    • This token would hopefully be usable from Storage, Correspondence, Dialogporten, Register, Profile etc
    • Tilby App/Ressurs Token for asyncrone prosesser altinn-authentication#769
  • Idea 2
    • Create a default/built in MaskinportenClient per app with some default scopes (e.g. instance.write)
    • Authorization would not be based on XACML policy
    • For Storage: send both Maskinporten token and Platform Access Token (PAT), so that InstanceEvents can be populated from PAT?
  • Idea 3
    • Create a MaskinportenClient + System user per app with some default scopes
    • Actions taken by this system user would then be better reflected in instance events/activity log, since we would solve this for system users in general
    • Would require XACML policy changes in apps
  • Idea 4
    • Custom Rich Authorization Request (RAR) flow for apps
    • Authorization would not be based on XACML policy
    • We can enforce JWKS access through k8s using ServiceAccounts

Analysis

Reasons for requiring an app-user/token:

  • Reliability
    • The process engine in Altinn.App.Core is the core component driving an instance forward. As of now, all tasks, transitions and therefore integrations are driven by the users request, and so practically anything that fails inside an app is returned to the client. In principle, the client request should only be concerned with wether or not the instance is in a valid state to transition to the next task of the process. Before initializing the next task (which may be an IServiceTask), we should be able to return a 200 OK to the client so that they can either wait for the next user-task or wait until a service task is complete (in practice we might just hold onto the client request if the next task also is process task requiring the users interaction, but the principle should hold). This naturally leads to errors in background processing, cleanup and service tasks being decoupled from clients (more work become async, and will require robust and configurable error handling). That however also means that we can't use the users token for example when writing to Storage as it may expire. In the future, process/next might even be triggered from background threads across reboots etc.
  • User-controlled/parallel signing
    • We need to delegate permissions that the instance owner doesn't have (we will be using the PlatformAccessToken for the Delegation API)
    • We need internal state related to the signing process that is owned by the app (strictly for bookeeping/reliability, and the user should not see this data directly)
    • We need to create Correspondence messages for each signee. Ideally the user shouldn't receive/see these messages before (technical requirement is that this type of process task needs to be implemented as a saga/state machine. Reliable, ordered execution of steps with atleast once delivery and idempotent handlers)
      • Read/sign permissions are delegated
      • The instance process has advanced to the signing task
    • When every signee has signed, we should be able to advance the process to the next task automatically and in the background (the last signee shouldn't necessarily be involved in the next task at all)
  • IServiceTask - BPMN Service Tasks
    • A few built-in ones: PdfServiceTask, EFormidlingServiceTask
    • Dialogporten future (phase 2?) implementation is likely to be implemented as a service TASK
    • Users can define their own service tasks. When they do, we need to have abstractions or configuration which they can use to express failure handling like retries. This implies that these tasks may run in the background irrespective of client activity (in the future). Therefore we will also need a way for the Execute function of these service tasks to access credentials and/or clients that can be used in the background, when an authorized client isn't present
  • Misc cleanup and bookkeeping
    • When creating datalements for signatures and PDFs, we need to make sure there is only one. There is cleanup logic present to handle cases where the users navigates back and forth between the signing and form tasks in which these dataelements have to be recreated. We should be able to do this bookeeping irrespective of the logged in users' permissions.
  • EFormidling and other features requiring Maskinporten integration (eFormidling itself does not require Maskinporten, but the dependency on Altinn Events does)
  • The eFormidling feature built into the app currently requires the user to also setup and configure Maskinporten auth. Ideally there was a simpler path to enabling eFormidling. Is eFormidling is supposed to be a built in feature/capability of Altinn 3, maybe apps should be authorized to integrate by default.
  • For eFormidling there is also code for sending a "reminder" event to Altinn Events, notifying back to the app itself that we need to check the status for the message order. The events client also requires the current users token (e.g. runtime cookie). If we were to support reliable async delivery in the process engine, we need to be able to do more in the background, and thus can't use the users token. The Altinn Events integration currently both uses the user-token and the PlatformAccessToken.
  • Other platform API such as Notification, Profile, Register could possibly also be useful for implementing service tasks, although they are not the primary drivers for us atm

Permissions needed for builtin functionality

  • altinn/instances.read altinn/instances.write
  • altinn/correspondence.write (for signing)
  • digdir:dialogporten

Slightly related:

  • Service owners need to build receiver systems that interact with the app/storage APIs. Large service owner orgs maybe have different teams maintaining different apps, in which case the org-scope becomes too broad in terms of auth. Ideally a service owner team could create client/resource to do more granular app level authorization aside from org-level. The app user/token scenario described in the issue is different (the app is the caller), but for receiver systems the caller will run outside Altinn/app clusters.

Conclusion

Initially we will go with idea 1 - custom/in-house solution using Altinn Authentication.

@martinothamar martinothamar added the status/draft Status: When you create an issue before you have enough info to properly describe the issue. label Oct 4, 2024
@martinothamar martinothamar self-assigned this Oct 4, 2024
@martinothamar martinothamar moved this to 🔎 Review in Team Apps Oct 4, 2024
@martinothamar martinothamar moved this from 🔎 Review to 👷 In Progress in Team Apps Oct 4, 2024
@martinothamar martinothamar removed the status/draft Status: When you create an issue before you have enough info to properly describe the issue. label Nov 29, 2024
@martinothamar martinothamar moved this from 👷 In Progress to ✅ Done in Team Apps Nov 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

No branches or pull requests

1 participant