🥜Nuss
Arminius adopts the modern OIDC-native approach of Matrix, sourcing out authentication to a separate component, the IdP (Identity Provider). In contrast to simpler applications, Matrix imposes some extended requirements on the IdP: First, Matrix allows users to choose arbitrary clients by design, so Dynamic Client Registration is an integral part of Matrix OIDC. Also, sessions are long-lived, so they should be manageable. For example, users must be able to log out lost devices remotely. Additionally, sessions are managed both by the IdP (e.g., the refresh token) and the homeserver (e.g., E2E device keys). To provide a good user experience and reduce the attack surface, the sessions on the IdP and on the homeserver should always be in-sync. These features are not commonly provided by third-party IdPs.
To bridge this gap, we provide Nuss (New User and Session Service) along with Arminius, although it is a separate component. For example, it uses a separate database and communicates with Arminius over SCIM and OIDC. It provides the SCIM extensions needed by the scim-client-component. Nuss aims not to implement any Matrix-specific behavior. All of its features could be reasonably implemented by other IdPs, although our SCIM extensions are not standardized.
Nuss contains an OIDC server providing long-lived sessions based on short-lived OIDC sessions from an upstream IdP (such as Zitadel). Nuss contains a SCIM client to sync users periodically from upstream. Nuss provides a webhook endpoint to trigger immediate SCIM synchronization from upstream. Nuss provides users and sessions as a SCIM server. Currently, only a small subset of SCIM is implemented in the server. The SCIM server implements a custom extension for incremental sync with long polling, so clients (such as Arminius) can watch for user or session changes.
Nuss itself connects to an upstream IdP with SCIM, to continuously synchronize the list of users in Nuss with the upstream IdP. This way, any user which is deactivated on the upstream IdP will quickly be deactivated in Nuss, and therefore in Arminius. Additionally, by regularly synchronizing the list of users via SCIM, they will show up in search on the Matrix homeserver immediately. Without SCIM, using only OIDC, users would only show up in search when Nuss became aware of them on their first login.
Implementation Goals
- No unauthenticated storage: Unauthenticated clients are unable to cause Nuss to store data, except logs. Motivation: Attackers aren’t able to fill up server storage. Attackers aren’t able to store illegal data on the server. The unauthenticated endpoints are stateless, so they can be scaled to infinity in case of DoS attacks.
- No unauthenticated server traffic: Unauthenticated clients are unable to cause Nuss to start any network requests or connections to other servers. Motivation: Attackers aren’t able to proxy DoS attacks through Nuss. They have to target other servers or Nuss directly.
Database
Nuss mostly follows the same conventions as Arminius, and it relies on arminius-lib-db for creating a database connection. There are some points where it currently deviates from conventions, including that queries are defined in a submodule rather than in a separate crate, and the nid naming convention for surrogate keys is not followed. Nuss autogenerates its own separate table descriptions.