Authentication

Last modified by Michael Hamann on 2024/05/06 17:59

When a chat or indexing request is submitted to the WAISE server, WAISE needs to know who submits this request in order to check rights accordingly, both for indexed content and for the usage of the LLM.

We identified the following functional requirements for authentication:

  1. External applications that want to index content need to authenticate
  2. Users that are authenticated in an application that embeds the WAISE chat need to be mapped to users and groups on the WAISE server to manage access to content and models

Further, as WAISE aims to be easily to embed in an existing application, authentication should be easy to implement for the existing application.

Chat

For a chat embedded in an Application A, we devised the following authentication scheme:

Preconditions:

Application A has a secret key, WAISE has a custom authenticator configured that knows the corresponding public key.

Authentication Process:

  1. Application A creates a JSON Web Token (JWT) and signs it with its secret key. The token contains username and a list of groups of the current user.
  2. Application A passes this token to the embedded WAISE chat.
  3. The chat submits this token with every request to the WAISE server. The WAISE server authenticates the user based on this token.
  4. When requesting content from Application A, WAISE might forward to token to Application A (or just the user name it extracted from it).

Requirements for the Administration:

  • Admins can configure external applications. For each application, a display name, a public key and a URL that will be checked as issuer claim on the token can be configured. Further, a group format pattern can be configured that will be used to format the group name(s). The configuration should also list all configured applications.
  • Optional: For each application, also a list of standard groups can be configured. All users that authenticate from the application will be added to these groups.
  • Optional: admins can configure how old a token can be at most.

Implementation:

A custom authenticator for WAISE handles token-based authentication. It only processes requests that contain an authentication token it can process. All other requests are forwarded to the regular XWiki authenticator or an admin-defined authenticator (like OIDC).

The authenticator validates the token, checking at least the following properties (based on these best practices):

  • The issuer matches the URL of one of the configured applications. This application is selected.
  • The signature algorithm matches the supported algorithm EdDSA
  • The token has not expired based on the expiration time
  • The expiration time is not more than 24 hours in the future
  • The not-before time isn't in the past  (just if present, and with a grace period of 30 seconds).
  • The token is not older than 24 hours based on the iat claim (issued at)
  • The token hasn't been issued in the future based on the iat claim (issued at)
  • The signature is from the public key of the selected application.
  • The audience includes the base URL of the wiki.

If the token is valid, the authenticator creates or updates an account for the user specified in the token. The user is identified by an extra XObject that is added on the user account that contains an identifier of the app it came from and the original username. The name of the user is derived from the original identifier but can be adjusted with a numeric suffix if an account of the same name exists already. The same is done for groups. Groups are updated whenever the groups contained in the token are different from the saved groups. This is meant as an easy way to update user information, not as a way to have different groups per request. If several requests with different groups are made at the same time, it is undefined which groups are used.

App Within Minutes is used to provide a user interface to manage the allowed applications, identified by their URL that is specified as issuer in the token. The PEM format is used to specify the Ed25519 public key in a portable way. A Java component reads these configurations and finds those that are authored by an admin and correspond to the application that is specified in the authorization header as issuer.

An object on the user profile is used to store issuer and subject to find back users that already authenticated using the token-based authenticator. An event listener cancels any update of this information by a non-admin user to prevent security issues by modifying the associated token information (to, e.g., get the groups of an admin user).

Limitations

Accounts created through the token authenticator won't be usable directly on the WAISE server and accounts created on the WAISE server won't be usable through the token authenticator. The chat UI could offer a way to set a password on an account created from an Application A to allow the use as a regular account on a WAISE server. Similarly, it could be imagined that a user could connect an account from Application A to an existing account through an authentication flow. Thereby, it would be possible to associate a WAISE account with several external applications and thus access content from several applications that require different accounts. However, these features aren't planned for the first version of the WAISE server.

Indexing

At the moment, by default, XWiki only provides the possibility to authenticate using basic auth on the REST API. While this is sufficient for an initial version, it would be nicer to authenticate using a token. For this the token mechanism for search could be re-used, but it seems overly complex as the private key needs to be always used to sign tokens, and it won't be possible to just assign a token to an existing user. A better approach would be to allow any user to generate a token that can be used as a replacement for their username and password.

A similar token authentication is used for the Nextcloud integration. The Nextcloud application uses the feature for token generation available in the OpenID Connect Provider. It doesn't seem that easily re-usable as there is no UI and this comes with quite some other features that might otherwise be undesirable. It might be easier to provide a custom solution for this. The following lists some ideas for this.

Requirements

  • Tokens need to be long-lived but should have an (optional?) expiration date
  • It should be possible to create a token in the user profile
  • It should be possible to see available tokens/their names and to revoke them
  • Optional: show when a token was last used
  • Optional: warn before a token expires

Implementation

  • Add a section to the user profile (UIX), see the User Profile Menu UIXP to generate and list tokens. Tokens could be listed using a Live Data.
  • Create an XClass to store tokens. Each token should have a name, an expiration date and a token stored as hash.
  • Tokens should be stored on the user profile. Each token is basically a password, but the token is generated as a randoms string that is displayed once and only stored hashed.
  • Implemented an authenticator that authenticates based on the stored tokens and forwards to the regular authenticator when no token is provided.
  • The authenticator should set a property in the execution context to mark it as being authenticated with the token.
  • Implement a document update listener that cancels any update to the user profile when the user is authenticated with a token.

This should be relatively easy to implement, offer a lot of flexibility and at least basic security in the sense that somebody who obtains a token cannot change the user profile and thus cannot issue new tokens or extend the lifetime of the existing tokens. Further, as the token itself is not stored, an attacker with read-only access to the database doesn't have any way to obtain a token. Tokens that grant script, admin, or programming right would still be dangerous as stored scripts would grant an attacker the ability to execute code outside the token authentication scope.

Ideally, tokens should only grant fine-grained access but this is hard or even impossible to achieve with XWiki's current architecture.

Get Connected