Federated Teams

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
This commit is contained in:
Maxence Lange
2025-05-19 17:11:58 +02:00
parent 11d817b20f
commit b9bb3cb80b
6 changed files with 453 additions and 0 deletions

View File

@@ -18,6 +18,7 @@ Table of contents
file_workflows/index
groupware/index
office/index
teams/index
reference/index
ai/index
webhook_listeners/index

View File

@@ -0,0 +1,143 @@
===============
Federated Teams
===============
Global Scale
------------
Teams is compatible with the Nextcloud Global Scale technology, allowing the grouping of entities from multiple instances.
We call Federated Team when a Team is set up to be functional on multiple instances and the only limit to it is that a Federated Team cannot be a member of a Team.
From a technical point of view, the instance that host the Team Owner account is considered to be the main instance for that Federated Team.
Every operations in relation to a Federated Team are initiated by a request to the Main Instance that will confirm permissions and broadcast the operation to
the rest of the instances of the Global Scale.
.. note::
While `Federated Teams` is available and working, some front-end elements might need some improvement. We are still working on
improving user experience when managing Teams over Global Scale.
.. note::
Global Scale requires to run Nextcloud Loopup Server v1.1.0 or above
Setup
-----
Each request between instance are authentified and a public/private key pairs needs to be generated on each instance of the Global Scale.
This is done by setting a unique url to reach the instance:
> ./occ circles:check --type internal
The configuration tool will ask for the internal address of the instance. This address needs to be reachable by all other instances of the Global Scale.
It also provide a way to test the address before saving. The operation require the administrator to execute few curl requests from another instance:
.. code-block::
$ ./occ circles:check --type internal
### Testing internal address.
. The internal setting should only be enabled if you are willing to use Circles in a GlobalScale setup on a local network.
. The address you need to define here is the local address of your Nextcloud, reachable by all other instances of our GlobalScale.
- Do you want to enable this feature ? (y/N) y
Please write down a new internal address to test: https://node1.example.com/
Do you want to check the validity of this internal address? (Y/n) y
You will need to run this curl command from a terminal on your local network and paste its result:
curl -L "https://node1.example.com/.well-known/webfinger?resource=http://nextcloud.com/&test=Lh9Zw3tyUYNbMHB"
paste the result here:
[pasting result from curl request #1]
First step seems fine.
Next step, please run this curl command from a terminal on your local network and paste its result:
curl -L "https://node1.example.com/index.php/apps/circles/?test=Lh9Zw3tyUYNbMHB" -H "Accept: application/json"
paste the result here:
[pasting result from curl request #2]
* Internal address looks good
- Do you want to save https://node1.example.com as your internal address ? (y/N) y
- Address https://node1.example.com is now used as internal
.. note:: This needs to be executed on every instance of the Global Scale
Authentication
--------------
Once every instance have their internal address and public/private key pairs set, you need to link each instance to the rest of the Global Scale.
This command needs to be executed on each instance of the Global Scale:
> ./occ circles:remote
.. code-block::
$ ./occ circles:remote
Adding node1.example.com: instance is local
Adding node2.example.com: ok
Adding node3.example.com: ok
+-------------------+-------------+-------------+--------------------+--------------------+-----------------------+
| Instance | Type | iface | UID | Authed | Aliases |
+-------------------+-------------+-------------+--------------------+--------------------+-----------------------+
| node2.example.com | GlobalScale | internal | 328b31d2b1e8fab5a8 | 328b31d2b1e8fab5a8 | ["node2.example.com"] |
| node3.example.com | GlobalScale | internal | ad3f46495b1897893b | ad3f46495b1897893b | ["node3.example.com"] |
+-------------------+-------------+-------------+--------------------+--------------------+-----------------------+
.. note:: In the future when adding a new instance to the Global Scale the ``./occ circles:remote`` needs to be executed on all instance, previously configured and freshly installed.
Federated Teams
---------------
When using Global Scale and a fully configured Circles/Teams app, every Team are considered Federated by default:
.. code-block::
node1$ ./occ circles:manage:create --type user admin1 "team_001"
Id: 3Il6hIXeOQbSfw5v26cDtBupRnIYbV3
Name: team_001
Owner: admin1
.. code-block::
node2$ ./occ circles:manage:list
+---------------------------------+----------+--------+--------+--------+------------------------------+------------+
| Single Id | Name | Config | Source | Owner | Instance | Population |
+---------------------------------+----------+--------+--------+--------+------------------------------+------------+
| 3Il6hIXeOQbSfw5v26cDtBupRnIYbV3 | team_001 | [] | Circle | admin1 | slave1.gs.artificial-owl.com | 1/-1 (1) |
+---------------------------------+----------+--------+--------+--------+------------------------------+------------+
.. code-block::
node1$ ./occ circles:member:add 3Il6hIXeOQbSfw5v26cDtBupRnIYbV3 user21@node2.example.com --type user
node1$ ./occ circles:members:list 3Il6hIXeOQbSfw5v26cDtBupRnIYbV3
+---------------------------------+-------------+---------------------------------+---------------------------------+------+-------------------+--------------------------+--------+------------+
| Circle Id | Circle Name | Member Id | Single Id | Type | Source | Username | Level | Invited By |
+---------------------------------+-------------+---------------------------------+---------------------------------+------+-------------------+--------------------------+--------+------------+
| 3Il6hIXeOQbSfw5v26cDtBupRnIYbV3 | team_001 | QhNdcj1EqfgZJOS1VVIAreb6KutqBaZ | s6XHTZs2TnVateDEYp6Pfjzch1664GE | user | Nextcloud Account | admin1 | Owner | occ |
| 3Il6hIXeOQbSfw5v26cDtBupRnIYbV3 | team_001 | UZELfc9zADPzJYYFD1kWpJCxB3vrCy9 | ahmhWEKPuoFNCQnERij2jk7MTR9XHeM | user | | user21@node2.example.com | Member | occ |
+---------------------------------+-------------+---------------------------------+---------------------------------+------+-------------------+--------------------------+--------+------------+
.. code-block::
node2$ ./occ circles:members:list 3Il6hIXeOQbSfw5v26cDtBupRnIYbV3
+---------------------------------+-------------+---------------------------------+---------------------------------+------+-------------------+--------------------------+--------+------------+
| Circle Id | Circle Name | Member Id | Single Id | Type | Source | Username | Level | Invited By |
+---------------------------------+-------------+---------------------------------+---------------------------------+------+-------------------+--------------------------+--------+------------+
| 3Il6hIXeOQbSfw5v26cDtBupRnIYbV3 | team_001 | QhNdcj1EqfgZJOS1VVIAreb6KutqBaZ | s6XHTZs2TnVateDEYp6Pfjzch1664GE | user | Nextcloud Account | admin1 | Owner | occ |
| 3Il6hIXeOQbSfw5v26cDtBupRnIYbV3 | team_001 | UZELfc9zADPzJYYFD1kWpJCxB3vrCy9 | ahmhWEKPuoFNCQnERij2jk7MTR9XHeM | user | | user21@node2.example.com | Member | occ |
+---------------------------------+-------------+---------------------------------+---------------------------------+------+-------------------+--------------------------+--------+------------+
.. code-block::
$ ./occ circles:member:list 3Il6hIXeOQbSfw5v26cDtBupRnIYbV3
+---------------------------------+-------------+---------------------------------+---------------------------------+------+-------------------+--------------------------+--------+----------------------------------+
| Circle Id | Circle Name | Member Id | Single Id | Type | Source | Username | Level | Invited By |
+---------------------------------+-------------+---------------------------------+---------------------------------+------+-------------------+--------------------------+--------+----------------------------------+
| 3Il6hIXeOQbSfw5v26cDtBupRnIYbV3 | team_001 | QhNdcj1EqfgZJOS1VVIAreb6KutqBaZ | s6XHTZs2TnVateDEYp6Pfjzch1664GE | user | | admin1@node1.example.com | Owner | occ@slave1.gs.artificial-owl.com |
| 3Il6hIXeOQbSfw5v26cDtBupRnIYbV3 | team_001 | UZELfc9zADPzJYYFD1kWpJCxB3vrCy9 | ahmhWEKPuoFNCQnERij2jk7MTR9XHeM | user | Nextcloud Account | user21 | Member | occ@slave1.gs.artificial-owl.com |
+---------------------------------+-------------+---------------------------------+---------------------------------+------+-------------------+--------------------------+--------+----------------------------------+
.. note::
Now, any file shared to the Team ``team_001`` by any its member will be available to every members of the Team.

View File

@@ -0,0 +1,12 @@
=====
Teams
=====
.. toctree::
:maxdepth: 2
setup
manage
globalscale

View File

@@ -0,0 +1,214 @@
============
Manage Teams
============
We will overview most of the ``occ`` commands useful to manage the Teams.
Remember that the ``contacts`` app allow your users to manage their own Teams from the web client.
Create a new team
-----------------
Team owner needs to be set at its creation:
.. code-block::
$ ./occ circles:manage:create <single_id> <team name>
The default type expected for the owner is its Single Id. However, it is possible to use a User Id if owner is a Nextcloud Account:
.. code-block::
$ ./occ circles:manage:create --type user user1 "My new Team"
Id: CLPKCiJAec3nh6dVEJpUPd5LashbbBc
Name: My new team
Owner: user1
Few options can be added to the command:
- ``--personal``: to set Team as `Personal` meaning members other than the owner will ever know they belongs to the Team but will still receive shared documents performed by the owner to the Team.
- ``--local`` `(Global Scale): a local Team will not be made available to other instances of the Global Scale.
Add a new member
----------------
.. code-block::
$ ./occ circles:members:add <team_id> <single_id>
Like when creating a new circle, the type of the entity can be specified using `--type`. The initiator of the operation can be optionally defined in the command:
.. code-block::
$ ./occ circles:members:add CLPKCiJAec3nh6dVEJpUPd5LashbbBc user2 --type user --initiator user1 --initiator-type user
List members
------------
You can get the list of current member of a Team
.. code-block::
$ ./occ circles:members:list <team_id>
.. code-block::
$ ./occ circles:members:list CLPKCiJAec3nh6dVEJpUPd5LashbbBc
+---------------------------------+-------------+---------------------------------+---------------------------------+------+-------------------+----------+--------+------------+
| Circle Id | Circle Name | Member Id | Single Id | Type | Source | Username | Level | Invited By |
+---------------------------------+-------------+---------------------------------+---------------------------------+------+-------------------+----------+--------+------------+
| CLPKCiJAec3nh6dVEJpUPd5LashbbBc | My new team | gAtwrBVTw23dEeEOSFlgLtI6z29v9wC | HNCBbYcmIqJCJdPraw8iPMFrZcELXvH | user | Nextcloud Account | user1 | Owner | occ |
| CLPKCiJAec3nh6dVEJpUPd5LashbbBc | My new team | A353C2dAQzBPk1vcmHu82EkkDZLJEy8 | kokKuOPeDv38caoGjbpM114mv3Et3XP | user | Nextcloud Account | user2 | Member | occ |
| CLPKCiJAec3nh6dVEJpUPd5LashbbBc | My new team | pR15xbRySW6chDP6UopP7c634Z1FPGd | LCdFtrJDzP2b28sYU5gGxfkrbHMwPMp | user | Nextcloud Account | user3 | Member | occ |
+---------------------------------+-------------+---------------------------------+---------------------------------+------+-------------------+----------+--------+------------+
List inheritance
----------------
A Team can be a member of an other Team and inheritance can be displayed for a better overview of your Teams.
As an example, we create 4 teams:
.. code-block::
$ ./occ circles:manage:create --type user user1 "Team A"
Id: 2AdmCjOXrT3vqqCjG2q7pnjUsNnf8Wy
Name: Team A
Owner: user1
$ ./occ circles:manage:create --type user user2 "Team B"
Id: oPkpu9EaFIFTH3E9p8wv6xPzb8nutPb
Name: Team B
Owner: user2
$ ./occ circles:manage:create --type user user3 "Team C"
Id: Vx1fYvIrsom94NOPDI7PKhGopSNJHGg
Name: Team C
Owner: user3
$ ./occ circles:manage:create --type user user4 "Team D"
Id: dfzo8Nikv4Nqsshr5FLskQhRJ3SR6cS
Name: Team D
Owner: user4
We now add ``TeamB`` as a member of ``TeamA`` and ``TeamC``+``TeamD`` as member of ``TeamB``. We also add some users to each teams:
.. code-block::
$ ./occ circles:members:add 2AdmCjOXrT3vqqCjG2q7pnjUsNnf8Wy oPkpu9EaFIFTH3E9p8wv6xPzb8nutPb
$ ./occ circles:members:add oPkpu9EaFIFTH3E9p8wv6xPzb8nutPb Vx1fYvIrsom94NOPDI7PKhGopSNJHGg
$ ./occ circles:members:add oPkpu9EaFIFTH3E9p8wv6xPzb8nutPb dfzo8Nikv4Nqsshr5FLskQhRJ3SR6cS
$ ./occ circles:members:add 2AdmCjOXrT3vqqCjG2q7pnjUsNnf8Wy --type user user6
$ ./occ circles:members:add 2AdmCjOXrT3vqqCjG2q7pnjUsNnf8Wy --type user user7
$ ./occ circles:members:add oPkpu9EaFIFTH3E9p8wv6xPzb8nutPb --type user user8
$ ./occ circles:members:add oPkpu9EaFIFTH3E9p8wv6xPzb8nutPb --type user user9
$ ./occ circles:members:add Vx1fYvIrsom94NOPDI7PKhGopSNJHGg --type user user10
$ ./occ circles:members:add Vx1fYvIrsom94NOPDI7PKhGopSNJHGg --type user user11
$ ./occ circles:members:add dfzo8Nikv4Nqsshr5FLskQhRJ3SR6cS --type user user12
$ ./occ circles:members:add dfzo8Nikv4Nqsshr5FLskQhRJ3SR6cS --type user user13
Now we display the list of all inherited members from the top Team ``Team A``:
.. code-block::
Name: Team A
Owner: user1@cloud.example.com
2AdmCjOXrT3vqqCjG2q7pnjUsNnf8Wy
├── iEw2kbdmULBJUhibSIb6iORRxHjK7e3 (Owner) MemberId: 93Po2zXqRvIDOhZX2aDLL7xYCXdo3Cu Name: user1 Source: Nextcloud Account
├── oPkpu9EaFIFTH3E9p8wv6xPzb8nutPb (Member) MemberId: iY5z6NJKaCLhSAcXySYJwbz85ppKZtQ Name: Team B Source: Circle
│ Owner: user2@cloud.example.com
│ │
│ ├── zEDSMW7Dlx4kj9aNLxWU7usvJs1TPFz (Owner) MemberId: VBtjTRrcZqaaHEztIRFqqDmfzF3s1ji Name: user2 Source: Nextcloud Account
│ ├── Vx1fYvIrsom94NOPDI7PKhGopSNJHGg (Member) MemberId: 9Sw6oADEkRVm6FxzBiGbStpZYLecUUU Name: Team C Source: Circle
│ │ Owner: user3@cloud.example.com
│ │ │
│ │ ├── V5KsaUuXSpWo1byC9TC9jyaIVjSS7mS (Owner) MemberId: Dvr7NjiEsGATbuHbdUHUFck9qjzB9C5 Name: user3 Source: Nextcloud Account
│ │ ├── t2wuuT2YtYFxg2WTRgf4LVPRT76av5U (Member) MemberId: gqJJHsWC1XGzaBvQKvqpCaSE5W3vjcD Name: user10 Source: Nextcloud Account
│ │ └── qRzbgRX9eSV9CBgfXnLAk5ugEUf3XSC (Member) MemberId: A4bkrZPZd8CrDhvYobo6TH2Z1U7keI2 Name: user11 Source: Nextcloud Account
│ │
│ ├── dfzo8Nikv4Nqsshr5FLskQhRJ3SR6cS (Member) MemberId: Zom2zOUVHkRIPlptlPfClZmNiUYPdPN Name: Team D Source: Circle
│ │ Owner: user4@cloud.example.com
│ │ │
│ │ ├── 5D4cVVuacHdg2naDTqrTdnxMaLidyq4 (Owner) MemberId: LZw6EjleAlOOfhHTfRljcggmrwf6pFS Name: user4 Source: Nextcloud Account
│ │ ├── Ky5IUBj2uHSMMxaGXswI8AdhWVILVKH (Member) MemberId: 96rn9rPMO46uNAlmZB7pjtRvplNeueT Name: user12 Source: Nextcloud Account
│ │ └── PIDY5McrqMA1FUUBs8oGolDBEmca1u5 (Member) MemberId: M5t7M1YVIY99ZDoBobfWncW3iLQMUcl Name: user13 Source: Nextcloud Account
│ │
│ ├── iHv31etw5bllowJAj7qTggYhQoWo5kW (Member) MemberId: UQGNHRw9koydXWjojlGWfOSTvi8bI8k Name: user8 Source: Nextcloud Account
│ └── dBTv1Vs3fMHYuZbGYAo3D4OSoXPm8Ed (Member) MemberId: 1uh4FPkWWf1fnGB3PsGDsCHMhtIzqxx Name: user9 Source: Nextcloud Account
├── cWykIF8qxi7I3kLMvdgwoBVZ8GRaWOx (Member) MemberId: uoYjKsopMbgzHFwSFO1x2Mclz9Da3Qi Name: user6 Source: Nextcloud Account
└── cEUd7yy6ekwsFBCWdoslz4Hgcb6x1s8 (Member) MemberId: pwnFSpyR8Mxqs7gWGyXejK8RnxFkoaA Name: user7 Source: Nextcloud Account
.. note:: while it is possible to invite a top Team (ie `Team A`) as member of a sub Team (ie `Team B`), the message ``(loop detected)`` will be shown in the tree.
Edit level
----------
Member level can be changed using
.. code-block::
$ ./occ circles:members:level <member_id> <level>
- `Member Id` is the unique id that idenfied an Entity within a Team
- `Level` accept those definitions: ``Member``, ``Moderator``, ``Admin``, ``Owner``
.. note:: The member level assigned to a sub Team is inherited to all members of the sub Team, and inherited to all members of eventual cascading sub Team
.. note:: An owner cannot be demoted from its ownership. But a new owner can be set as Owner of a Team, replacing the previous Owner.
Remove a member
---------------
Using its `Member Id` a member can be removed from a Team:
.. code-block::
$ ./occ circles:members:remove <member_id>
List memberships
----------------
It is also possible to list all memberships of an entity using
.. code-block::
$ ./occ circles:memberships <single_id>>
The result is also display as a tree, in case of inherited memberships:
.. code-block::
$ ./occ circles:membership --type user user1
Id: user1
Instance: cloud.example.com
Type: user
SingleId: iEw2kbdmULBJUhibSIb6iORRxHjK7e3
Memberships:
(database not updated)
- 2AdmCjOXrT3vqqCjG2q7pnjUsNnf8Wy (Owner)
- Vx1fYvIrsom94NOPDI7PKhGopSNJHGg (Member)
- iEw2kbdmULBJUhibSIb6iORRxHjK7e3 (Owner)
- oPkpu9EaFIFTH3E9p8wv6xPzb8nutPb (Moderator)
iEw2kbdmULBJUhibSIb6iORRxHjK7e3
└── 2AdmCjOXrT3vqqCjG2q7pnjUsNnf8Wy (Team A) MemberId: 93Po2zXqRvIDOhZX2aDLL7xYCXdo3Cu Level: Owner
Owner: user1@cloud.example.com
└── Vx1fYvIrsom94NOPDI7PKhGopSNJHGg (Team C) MemberId: kEqPRIC7iPC4ihau7RGBw6ou6YvDWRK Level: Member
Owner: user3@cloud.example.com
└── oPkpu9EaFIFTH3E9p8wv6xPzb8nutPb (Team B) MemberId: 9Sw6oADEkRVm6FxzBiGbStpZYLecUUU Level: Moderator
Owner: user2@cloud.example.com
└── 2AdmCjOXrT3vqqCjG2q7pnjUsNnf8Wy (Team A) MemberId: iY5z6NJKaCLhSAcXySYJwbz85ppKZtQ Level: Member (Owner)
Owner: user1@cloud.example.com
(loop detected)

View File

@@ -0,0 +1,82 @@
============
Introduction
============
Concept
-------
Teams is a feature allowing your users to create their own group of users, including local and external accounts. This is the list of what can be set as member of a Team:
- users from local Nextcloud,
- groups from local Nextcloud,
- mail addresses,
- other Teams.
Teams offers different levels to allow certain actions:
- members - normal member of the team
- moderators - can invite and remove team members,
- administrators - can edit team's settings,
- owner - can delete the team. Each Team must have one single owner.
.. note::
When adding a Nextcloud Group or an other Team into a Team, as member, the grade applied to this membership is inherited
to all members of the invited Nextcloud Group or Team, cascading recursively if this sub Team contains itself more Groups/Teams.
Teams is compatible with the Global Scale technology and permit the grouping of Nextcloud Accounts across multiple instances.
.. note::
While Teams can be managed with the `./occ` command by administrators, the Nextcloud Contacts app is advised for a better user experience
First steps
-----------
To avoid running heavy process and damage the user experience, the Teams app requires to send an HTTP request on itself, like a loopback.
While the loopback address is easily detectable by the app it might require, on some setup, a human intervention.
If you are facing unresponsive behavior when managing your Teams, or want to ensure a correct setup, please run this command:
.. code-block::
$ ./occ circles:check --type loopback
### Checking loopback address.
. The loopback setting is mandatory and can be checked locally.
. The address you need to define here must be a reachable url of your Nextcloud from the hosting server itself.
. By default, the App will use the entry 'overwrite.cli.url' from 'config/config.php'.
* testing current address: https://cloud.example.net
- GET request on https://cloud.example.net/index.php/csrftoken: 200
- POST request on https://cloud.example.net/index.php/apps/circles/async/test-dummy-token/: 200
- Creating async FederatedEvent f9a69f7c-2eb5-4018-ab4b-f983fb38ded8 (took 99ms)
- Waiting for async process to finish (5s)
- Checking status on FederatedEvent verify=17 manage=42
* Loopback address looks good
Configuration
-------------
Configuration is done using the ``./occ`` command, and Teams comes with a list of config keys:
- **limit_circle_creation** ``<singleId>`` - limit the creation of new Teams to an entity, using entity single id.
- **hard_moderation** ``[0 (default), 1, 2]`` - define if a moderator/admin/owner can promote/demote an other entity to its own same level.
``0`` means initiator needs to be same level than action and recipient: a moderator can promote another member moderator,
``1`` means initiator needs to overrank the recipient: only an admin can demote a moderator,
``2`` means initiator needs to overrank the action: only an admin can promote a moderator.
- **frontend_enabled** ``[0, 1 (default)]`` - disable the OCS API.
- **keyhole_cfg_request** ``[0 (default), 1]`` - non members of a Team can access its members list.
- **route_to_circle** - setup the app+route to display details about a Team.
- **enforce_password** ``[0 (default), 1]`` - enforce the generation of a password for external members on share, for all teams.
- **creation_activity** ``[0 (default), 1]`` - create a new activity on Team creation.
- **members_limit** - limit the number of members per Team
- **self_signed_cert** ``[0 (default), 1]`` - allow self signed certificate (in global scale setup).
.. note::
Configuration is applied with this format:
``./occ config:app:set circles <config_key> --value <config_value>``

Submodule build/openapi-extractor added at d99e9c0fba