Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 205 additions & 0 deletions docs/adr/0003-guest-users.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
---
title: "Guest users in OpenCloud"
---

* Status: pending
* Deciders: []
* Date: 2026-01-20

Reference: https://github.com/opencloud-eu/opencloud/issues/2111

## Context and Problem statement

To allow collaboration with external Users (Users that don't yet have an
account in the IDP, and might be external to the organization), it should
be possible to invite "Guest Users" into an OpenCloud instance.

## Requirements

- the audit trail of the external user accessing the resource needs to
be maintained, that means sharing via a password protected public link
is not sufficient as access to that one is tracked as if the creator
of the link accessed the resource
- external users need to be authenticated just like "normal" users, when
accessing the shared resource (including the possibility to use 2FA)
- the ability to invite external users is tied to a separate permission
(e.g. "can invite guest users")
- make it work with all (most) of the user-management configurations we support.
The built-in IDP (lico) does not need to be supported.
- avoid creating "Shadow IT" Infrastructure, e.g. we don't want to
create/maintain a separate IDP instance just for Guest User that would
allow bypassing corporate rules for Identity Management
- the process of inviting a guest must can be asynchrounous, i.e. the user
account of the guest user might not be created at the moment of
creating the share/sending the invitaion as the whole process crosses
multiple systems (OpenCloud, Identity Management System, Email) and might
even require manual steps.
- It should be possible to "convert" a guest user into a "normal" user without
the user loosing their shares.
- Guest user invitations should have an expiration date, after which they can
no longer be accepted.


### Privileges of guest users

- guest users can not share or invite other users to a space or create public
links. (primary focus of the feature is to provide a simple way to grant
external, authorized access. anything else like resharing would undermine
regular user accounts).
- guestusers can use the desktop and mobile client to access their shares or spaces


- all "normal" users are able to share with guest users, just as if they where "normal" users.


## Questions still to be answered

- what's the life cycle of a guest user?
- Who's responsible for deprovisioning?
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest users with the role "admin"

- Do guest users expire after a certain time?
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default: guest user accounts expire after 120 days of inactivity (=no login), can be configured. the invitation expires after 30 days per default. can be configured.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default: guest user accounts expire after 120 days of inactivity (=no login), can be configured

This is where the whole thing gets murky again. I don't think we can reliably provide such a feature and keep the promise of working with all kinds external IDPs. Locking inactive user accounts is usually a feature of the IDP, we're not an IDP.

the invitation expires after 30 days per default. can be configured.

- Do we need to keep track of who invited whom and when? (not just in
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. there needs to be a lowlevel option to manage guest users eg. via cmd.
Guest user management must also be possible via a dashboard which is by default an external system with these options in the ui (same options should be availbale via cmd):

list all email adresses:

  • email adress (=guest user)
  • status (invitation accepted / pending)
  • invited by
  • invitation date
  • if accepted: invitation accepted date
  • last login
  • days left until expiration + absolute date (updates after every login)

actions:

  • export list as CSV
  • deactivate/activate login (triggers infomail to guestuser)
  • delete invite/user (triggers infomail to guestuser)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • deactivate/activate login (triggers infomail to guestuser)

  • delete invite/user (triggers infomail to guestuser)

See my other comment above. In a "normal" setup with an external IDP the OpenCloud admin is not able to delete users. As "guest" users are supposed to come from the same IDP, we will also not be able to delete those.

Somehow I think we need to get a common understand of the whole "lifecycle of an OpenCloud user". I have the feeling everybody has a different understanding of what OpenCloud really should provide in that area.

the audit log?)
- What if the user already exists but used a different mail address in
his account (e.g. sub-addressing?).

## Obstacles

### UserIDs

- Every user in OpenCloud needs to have a userid assigned
- Sharing, as many other features, needs that userid for storing the
share (share service) and for assigning the grants on the shared
resources (storage provider)
- When an external IDP is used the generation of that userid is usually
not in control of OpenCloud (exception User-Autoprovisioning, or when
the Provisioning/Education API is used). In that case, the userid is
taken from a LDAP Attribute maintained in the external system

### Lots of identity management options

- OpenCloud provides many different ways to consume user-accounts. Guest
users are supposed to be working with all/most of them:
- External IDP, with external LDAP service
- External IDP, with manual provisioning via the
Education/Provisioning APIs (to a local OpenCloud specific LDAP
service) - e.g. in multi-tenant setups
- External IDP, with User-Autoprovisioning (also to a local OpenCloud
specific LDAP service)
- everything in-between and outside of the above
- Each of these options have different ways for user-provisioning and in
the way userids are generated and managed

### How do we keep track of invitations?

- Completely rely on external system?
- Track creation and acceptance of invitations somehow?
- Do invitation expire at some point?

## Possible solutions

### Re-vitalize the PoC implementation of the invitations service and finalize it (<https://github.com/opencloud-eu/opencloud/blob/main/services/invitations/README.md>)

- Implements parts of the MSGraph Invitation Specification
(<https://learn.microsoft.com/en-us/graph/api/resources/invitation?view=graph-rest-1.0>)
- Currently there's just a single backend that allows creating users,
using the Keycloak Admin API
- As part of the user creation keycloak triggers an email to be sent to
the invited user to get him to verify his email address and set a
password. This is not really and invitation email.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is not enough. We need to be in control of that EMail probably.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exactly do you mean by that?


#### Pros

- A partial implementation already exists
- no shadow IT

#### Cons

- while the emails sent by keycloak can be themed. There is no way
to add custom content, like: "you've being invited by user X to
access resource Y"
- the keycloak admin API does not return the password reset link in
the response, so we can't use that to send a custom email
- the keycloak implementation is not a real "user invitation"
workflow, the user experience for the invited user is not ideal
- The workflow likely only works with a limited set of setups.
(Specifically: a keycloak that is able to write into a connected
LDAP database, that OpenCloud can consume)
- As the invitations are not really tracked, e.g. we don't really
"know" if an invitation was accepted
- Requires direct access to the Identity Management System

### Invitation Service + support for pending shares in the share manager

- Create some form in invitation manager and provide tools/documentation
for customers to hook that up with their Identity Management System
- User's with the "right" privileges are able to create invitations,
invitations get a unique identifier. Other data maintained on the
invitation:
- Invited user's email address
- Invited user's userid (once the user account was provisioned)
- Inviting user's userid
- Creation timestamp
- Invitation State (Pending, Accepted, …)
- (more probably)
- our sharing API
('graph/v1beta1/drives/{drive-id}/items/{item-id}/invite') is enhanced
to allow creating shares that target an invitation as the share
recipient. (That share would only be persisted in the 'shares' service
and would not yet crate any grants on the filesystem, or send out
sharing notifications). (Requires changes to the CS3 sharing APIs)
- A middleware (specific to the Identity Management System) is
"informed" (e.g. via web hooks or a message queue) when a new
invitation is created. That middleware is responsible for provisioning
the user account of the guest user. Whatever this process looks like
it completely up to the middleware (maybe it triggers some invitation
workflow or it could just even open a support ticket with the IDP
admin)
- once the user is provisioned the middleware calls back into our
invitations service,marks the invitation as "accepted" and provides
the "userid" of the guest user. The invitations service then triggers
the "pending" shares to be processes, which causes the filesystem
grants to be written and notifications to be send out to the guest
user.
- We'd provide a reference implementation of that middleware, that works
with keycloak

#### Pros

- Agnostic to whatever Identity Management System is used
- We have an audittrail about who was invited by whom at what point
in time
- no shadow IT

#### Cons

- somewhat complex
- likely requires changes to the CS3 APIs

#### Implementation Obstacles

- Permissions on spaces are currently not tracked in the share
manager, the are purely managed via grants. So currently the share
manager service currently does not know anything about (invited)
users being assigned to spaces
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the share manager need to know about invited or even accepted guest users? Is't that just a second call to the invitation manager to get that info where needed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is't that just a second call to the invitation manager to get that info where needed?

Could you please elaborate on that?


## Additional thoughts

If OpenCloud were responsible for allocating the UserIDs of all users
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! I was wondering also, if that could simplify things in the future and let us get rid of the LDAP dependency.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICT always having opencloud generate a userid would allow us to get rid of the shared ldap deployment mode. The ldap server would only be used to find recipients (users or groups) in an organization. We always only send invitations into some form of inbox of a user. This could literally be an email. Or an internal nats queue with invites.
Then, when he follows the invite link, we not only provision their personal space (guest users don't have one) but the invite they followed (the creat home call can add the grant). Invites are actually not a new concept. IMO it is just a better name for a pending share (they have three states: pending, accepted and declined).
When sharing with 'internal' users the invite service can take the responsibility of creating grants and accepting them instead of creating invites.

Anyway, IIRC we bounced around the idea of exchanging the sub+iss, basic auth or app password credentials in the proxy with a userid generated by opencloud years ago already. It has seeveral benefits:

  1. we can assign credentials and multiple identities (as in multiple Identity Providers) to an account. This allows migrating accounts from one IdP to another as the grants on disk can keep the same userid.
  2. we can add a scim_id as an identitiy, which would make some use cases follow the standard integration of SCIM and OpenID Connect we could use SCIM to provision a guest account in the Identity management system.

The last point addresses the problem that if a user shares with a guest, aka an email address, that needs to trigger an onboarding process for the new guest. If we just create a new user in a keycloak that we have write permission to we are back at the same shadow it user management as before.

We could use OpenID Connect Discovery to find the external issuer and trust that to authenticate users. OIDC in theory is federated. However, in practice our clients would have to dynamically register with the guests IdP ... which does not seem to be widely supported, yet.

I think we should use a list of trusted identity providers, this would allow a single instance to use multiple identity providers, eg for multi tenancy use cases or when organization merge and multiple idps exist for a wile or to better reflect the sovereignty of organizations.

If no idp is responsible for the guest email, we can use a fallback idp that is only used for guest accounts. We already have the webfinger service that we can use for the issuer discovery.

So ... yes, please ... make opencloud generate a userid.

the solution sketch above would likely loose some of its complexity. We
would "roll" the userid for the invited user already when creating the invite.
That would allow to skip the step of creating a "pending" Share with an
invitation assigned. As we have an ID already, we could just create a "normal"
share and even populate the grants on the filesystem for that share (or space)

We've been pondering on the idea of making OpenCloud manage all UserIDs
for quite a while as it would have some additional benefits for the
whole user management story.

- We wouldn't rely anymore on the external Identity Management system to
provide a unique id with certain properties. Ideally the only unique
thing we'd need from the external system is the `iss` and `sub`
claims of the IDP and those are required by the OIDC standards.

It could be worth to spend some time on figuring out a migration path
towards such a solution, before spending resources on a complex guest
features implementation.