Skip to content

Commit

Permalink
Document role service
Browse files Browse the repository at this point in the history
  • Loading branch information
jirik committed Jan 3, 2024
1 parent a617ecc commit ca516b4
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 14 deletions.
13 changes: 8 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@
```
LAYMAN_CLIENT_VERSION=73a6d0b5d2138e62077d305d07b4992d020168c8
```
- Stop using environment variable `LAYMAN_GS_ROLE_SERVICE`, it has no effect to Layman anymore. Layman now uses [role service](doc/security.md#role-service) identified by new environment variable [LAYMAN_ROLE_SERVICE_URI](doc/env-settings.md#LAYMAN_ROLE_SERVICE_URI). The service is called `layman_role_service` on GeoServer.
- Set new environment variable [LAYMAN_ROLE_SERVICE_URI](doc/env-settings.md#LAYMAN_ROLE_SERVICE_URI)
- Stop using environment variable `LAYMAN_GS_ROLE_SERVICE`, it has no effect to Layman anymore. Role service called `layman_role_service` is used now.
### Migrations and checks
#### Schema migrations
- [#165](https://github.com/LayerManager/layman/issues/165) Add column `role_name` to table `rights` in prime DB schema. Add constraint that exactly one of columns `role_name` and `id_user` is not null.
- [#164](https://github.com/LayerManager/layman/issues/165) Create internal GeoServer [JDBC Role Service](https://docs.geoserver.org/2.21.x/en/user/security/usergrouprole/roleservices.html#jdbc-role-service) DB schema `_role_service`.
- [#165](https://github.com/LayerManager/layman/issues/165) Create DB schema `_role_service` that can be used as [role service](doc/security.md#role-service).
#### Data migrations
### Changes
- [#165](https://github.com/LayerManager/layman/issues/165) New REST endpoint [GET Roles](doc/rest.md#get-roles) with list of all roles registered in [JDBC Role Service](https://docs.geoserver.org/2.21.x/en/user/security/usergrouprole/roleservices.html#jdbc-role-service), that can be used in access rights. This new endpoint was added to Test Client into tab "Others".
- [#165](https://github.com/LayerManager/layman/issues/165) POST Workspace [Layers](doc/rest.md#post-workspace-layers)/[Maps](doc/rest.md#post-workspace-maps) and PATCH Workspace [Layer](doc/rest.md#patch-workspace-layer)/[Map](doc/rest.md#patch-workspace-map) saves [role names](doc/models.md#role) mentioned in `access_rights.read` and `access_rights.write` parameters into DB.
- [#165](https://github.com/LayerManager/layman/issues/165) Many endpoints respect role access rights:
- [#165](https://github.com/LayerManager/layman/issues/165) Prior to this version, Layman enabled to use [usernames](doc/models.md#username) and pseudo-role `EVERYONE` in access rights. From now on, Layman accepts also [role names](doc/models.md#role).
- [#165](https://github.com/LayerManager/layman/issues/165) Roles (except of `EVERYONE`) are managed by [role service](doc/security.md#role-service).
- [#165](https://github.com/LayerManager/layman/issues/165) New REST endpoint [GET Roles](doc/rest.md#get-roles) with list of all roles registered in [role service](doc/security.md#role-service), that can be used in access rights.
- This new endpoint was added to Test Client into tab "Others".
- [#165](https://github.com/LayerManager/layman/issues/165) POST Workspace [Layers](doc/rest.md#post-workspace-layers)/[Maps](doc/rest.md#post-workspace-maps) and PATCH Workspace [Layer](doc/rest.md#patch-workspace-layer)/[Map](doc/rest.md#patch-workspace-map) saves [role names](doc/models.md#role) mentioned in `access_rights.read` and `access_rights.write` parameters into [prime DB schema](doc/data-storage.md#postgresql).
- [#165](https://github.com/LayerManager/layman/issues/165) Many requests respect roles in access rights:
- [GET](doc/rest.md#get-workspace-layer)/[PATCH](doc/rest.md#patch-workspace-layer)/[DELETE](doc/rest.md#delete-workspace-layer) Workspace Layer
- GET Workspace Layer [Thumbnail](doc/rest.md#get-workspace-layer-thumbnail)/[Style](doc/rest.md#get-workspace-layer-style)/[Metadata Comparison](doc/rest.md#get-workspace-layer-metadata-comparison)/[Chunk](doc/rest.md#get-workspace-layer-chunk)
- [GET](doc/rest.md#get-workspace-map)/[PATCH](doc/rest.md#patch-workspace-map)/[DELETE](doc/rest.md#delete-workspace-map) Workspace Map
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,11 @@ When providing **external dependencies**, check their production-related documen

Within PostgreSQL, you need to provide one database for Layman and one database for Micka. For Layman, you also need to provide one user [LAYMAN_PG_USER](doc/env-settings.md#LAYMAN_PG_USER) who needs enough privileges to create new schemas in [LAYMAN_PG_DBNAME](doc/env-settings.md#LAYMAN_PG_DBNAME) database. The user also needs access to `public` schema where PostGIS must be installed.

If you are using other DB schema than [internal role service schema](doc/security.md#internal-role-service-schema) as [role service](doc/security.md#role-service), you need to provide all [admin records](doc/security.md#admin-role-service-records).

Within QGIS Server, you do not need to provide anything special.

Within GeoServer, you need to provide either admin password [GEOSERVER_ADMIN_PASSWORD](doc/env-settings.md#GEOSERVER_ADMIN_PASSWORD), or one Layman user [LAYMAN_GS_USER](doc/env-settings.md#LAYMAN_GS_USER) and one layman role [LAYMAN_GS_ROLE](doc/env-settings.md#LAYMAN_GS_ROLE). If admin password is provided, Layman will create the Layman user and the Layman role automatically. URL path of the GeoServer must be `/geoserver/`.
Within GeoServer, you need to provide either admin password [GEOSERVER_ADMIN_PASSWORD](doc/env-settings.md#GEOSERVER_ADMIN_PASSWORD), or one Layman user [LAYMAN_GS_USER](doc/env-settings.md#LAYMAN_GS_USER). If admin password is provided, Layman will create the Layman user automatically. URL path of the GeoServer must be `/geoserver/`.

Within Redis, you need to provide two databases, one for Layman, second for Layman Test Client. Connection strings are defined by [LAYMAN_REDIS_URL](doc/env-settings.md#LAYMAN_REDIS_URL) and [LTC_REDIS_URL](doc/env-settings.md#LTC_REDIS_URL).

Expand Down
7 changes: 4 additions & 3 deletions doc/data-storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,11 @@ Data is saved to LAYMAN_DATA_DIR directory, LAYMAN_QGIS_DATA_DIR directory, and
Filesystem is used as persistent data store, so data survives Layman restart.

### PostgreSQL
Layman uses directly **one database** specified by [LAYMAN_PG_DBNAME](env-settings.md#LAYMAN_PG_DBNAME) to store data. There are two kinds of schemas in such database:
Layman uses directly **one database** specified by [LAYMAN_PG_DBNAME](env-settings.md#LAYMAN_PG_DBNAME) to store data. There are three kinds of schemas in such database:
- [LAYMAN_PRIME_SCHEMA](env-settings.md#LAYMAN_PRIME_SCHEMA) that holds information about
- users, workspaces, and publications including access rights
- data version including migration ID
- [Internal Role Service Schema](security.md#internal-role-service-schema) with table and view structure that can be used as [role service](security.md#role-service)
- Schemas holding vector layer data.
- One **[workspace schema](https://www.postgresql.org/docs/13/ddl-schemas.html)** is created for every created [workspace](models.md#workspace). Name of workspace schema is always the same as workspace name.
- One **[table](https://www.postgresql.org/docs/13/sql-createtable.html)** is created in workspace schema for each layer published with input vector files. Name of the table is in form `layer_<UUID>` with `-` replaced with `_`, e.g. `layer_96b918c6_d88c_42d8_b999_f3992b826958`. The table contains data from vector data files.
Expand All @@ -115,7 +116,7 @@ Data changes made directly in vector data DB tables (both internal and external)
PostgreSQL is used as persistent data store, so data survives Layman restart.

### GeoServer
**[User](https://docs.geoserver.org/2.21.x/en/user/security/webadmin/ugr.html)** and **[role](https://docs.geoserver.org/2.21.x/en/user/security/webadmin/ugr.html)** are created for every [user](models.md#user) who reserved [username](models.md#username). User name on GeoServer is the same as username on Layman. Role name is composed a `USER_<upper-cased username>`.
**[User](https://docs.geoserver.org/2.21.x/en/user/security/webadmin/ugr.html)** is created for every [user](models.md#user) who reserved [username](models.md#username). Username on GeoServer is the same as username on Layman.

Two **[workspaces](https://docs.geoserver.org/2.21.x/en/user/data/webadmin/workspaces.html)** are created, each with one **[PostgreSQL datastore](https://docs.geoserver.org/2.21.x/en/user/data/app-schema/data-stores.html#postgis)**, for every [workspace](models.md#workspace) (both personal and public). First workspace is meant for [WFS](endpoints.md#web-feature-service) and has the same name as the workspace on Layman. Second workspace is meant for [WMS](endpoints.md#web-map-service) and is suffixed with `_wms`. Name of the datastore is `postgresql` for both workspaces. Every workspace-related information (including PostgreSQL datastore) is saved inside workspace.

Expand All @@ -127,6 +128,6 @@ For each vector layer with QML style, **[Feature Type](https://docs.geoserver.or

For each raster layer, **[Coverage Store](https://docs.geoserver.org/2.21.x/en/user/rest/api/coveragestores.html)**, **[Coverage](https://docs.geoserver.org/2.21.x/en/user/rest/api/coverages.html)**, and **[Style](https://docs.geoserver.org/2.21.x/en/user/styling/webadmin/index.html)** are created in WMS workspace. If layer is [timeseries](models.md#timeseries), Coverage Store is [ImageMosaic](https://docs.geoserver.org/2.21.x/en/user/data/raster/imagemosaic/index.html), otherwise it is [GeoTIFF](https://docs.geoserver.org/2.21.x/en/user/data/raster/geotiff.html). Names of Coverage and Style are the same as layername, name of Coverage Store is prefixed with `geotiff_` or `image_mosaic_` depending on its type. Coverage Store and Coverage points to appropriate normalized raster GeoTIFF file(s). Style contains visualization file.

Two **[access rules](https://docs.geoserver.org/2.21.x/en/user/security/layer.html)** are created for each layer in each GeoServer workspace (WFS and WMS), one for [read access right](security.md#publication-access-rights), one for [write access right](security.md#publication-access-rights). Every username from Layman's access right is represented by user's role name (i.e. `USER_<upper-cased username>`). Role `EVERYONE` is represented as `ROLE_ANONYMOUS` on GeoServer.
Two **[access rules](https://docs.geoserver.org/2.21.x/en/user/security/layer.html)** are created for each layer in each GeoServer workspace (WFS and WMS), one for [read access right](security.md#publication-access-rights), one for [write access right](security.md#publication-access-rights). Every username from Layman's access right is represented by user's role name (i.e. `USER_<upper-cased username>`). Role `EVERYONE` is represented as `ROLE_ANONYMOUS` and `ROLE_AUTHENTICATED` on GeoServer.

GeoServer is used as persistent data store, so data survives Layman restart.
2 changes: 1 addition & 1 deletion doc/env-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ List of [users](models.md#user) and [roles](models.md#role) giving them permissi
List of [users](models.md#user) and [roles](models.md#role) giving them permission to publish new [publication](models.md#publication) in already created [public workspace](models.md#public-workspace).

### LAYMAN_ROLE_SERVICE_URI
URL of Role Service with schema in format `postgresql://<username>:<password>@<host>:<port>/<dbname>?schema=<schema_name>`. If you want to use internal Role Service, set it to `postgresql://<LAYMAN_PG_USER>:<LAYMAN_PG_PASSWORD>@<LAYMAN_PG_HOST>:<LAYMAN_PG_PORT>/<LAYMAN_PG_DBNAME>?schema=_role_service` (replace variable names with their values). URL scheme must be `postgresql`. URL host must be mentioned explicitly, as well as DB schema in `schema` URL query parameter.
URL of [Role Service](security.md#role-service) with DB schema in format `postgresql://<username>:<password>@<host>:<port>/<dbname>?schema=<schema_name>`. URL scheme must be `postgresql`. URL host must be mentioned explicitly, as well as DB schema in `schema` URL query parameter. If you want to use [internal role service schema](security.md#internal-role-service-schema) provided by Layman, set value to `postgresql://<LAYMAN_PG_USER>:<LAYMAN_PG_PASSWORD>@<LAYMAN_PG_HOST>:<LAYMAN_PG_PORT>/<LAYMAN_PG_DBNAME>?schema=_role_service` (replace variable names with their values).

## Layman Test Client Settings

Expand Down
7 changes: 6 additions & 1 deletion doc/models.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,25 @@
- User is any person who communicates with Layman REST API through any client.
- User can be either authenticated, or unauthenticated (i.e. anonymous).
- User is sometimes identified by [username](#username)
- List of users with usernames can be obtained by [GET Users](rest.md#get-users).

## Username
- Username is a string identifying one [user](#user), so it is unique among all users.
- The string is lower-case (in contrast with [role name](#role)).
- Each user is represented by max. one username.
- Username is also used to identify user's [personal workspace](#personal-workspace) when communicating with [Layman REST API](rest.md).
- Username can be reserved by [PATCH Current User](rest.md#patch-current-user).
- Usernames can be used for assigning access rights.
- Anonymous user has no username.

## Role
- Role is any group of users. One user can be assigned to multiple roles.
- Each role is identified by name that is unique among all roles.
- The name is upper-case (in contrast with [username](#username)), maximum length is 64 characters.
- Roles can be used for assigning access rights.
- Role names can be used for assigning access rights.
- Existing roles can be obtained by [GET Roles](rest.md#get-roles).
- There is always listed special pseudo-role `EVERYONE` that represents every user including anonymous (unauthenticated).
- Roles (except of `EVERYONE`) are managed by [role service](security.md#role-service).

## Workspace
- Workspace is folder for [publications](#publication).
Expand Down
2 changes: 1 addition & 1 deletion doc/rest.md
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +856,7 @@ HTTP status code 200 if credentials were deleted.
`/rest/roles`

### GET Roles
Get list of roles.
Get list of [roles](models.md#role) available in [role service](security.md#role-service) in table `roles` except of [admin records](security.md#admin-role-service-records). Pseudo-role `EVERYONE` appear in the list too.

#### Request.
No action parameters.
Expand Down
45 changes: 43 additions & 2 deletions doc/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ Access rights enable user to control access to publications. Access to each publ
- grants deleting the publication by `DELETE` HTTP request to [multi-publication REST API endpoints](#access-to-multi-publication-endpoints)
- grants WFS-T requests to the layer

Both read and write access rights contain list of [user names](models.md#username) or [role names](models.md#role). Currently, Layman accepts following roles:
- `EVERYONE`: every user including anonymous (unauthenticated)
Both read and write access rights contain list of [usernames](models.md#username) or [role names](models.md#role).

Users listed in access rights, either directly or indirectly through roles, are granted to perform described actions.

Expand All @@ -71,3 +70,45 @@ Access is treated by following rules:

It's analogical for maps.

### Role Service
Despite of [usernames](models.md#username), [role names](models.md#role) are not controlled by Layman, but by **role service**.

Role service can be any PostgreSQL DB schema containing table (or view, or materialized view) structure described in [GeoServer documentation](https://docs.geoserver.org/2.21.x/en/user/security/usergrouprole/roleservices.html#jdbc-role-service). Furthermore, Layman has special requirements to records in the tables. There are two types of records: [admin records](#admin-role-service-records) and [business records](#business-role-service-records). No other records are allowed.

Role service is used by both Layman and GeoServer when [access rights](#publication-access-rights) are evaluated.

Role service is identified by [LAYMAN_ROLE_SERVICE_URI](env-settings.md#LAYMAN_ROLE_SERVICE_URI). It can contain URI to any PostgreSQL schema that meets mentioned requirements, e.g. to [internal role service schema](#internal-role-service-schema).

#### Admin role-service records

Admin records are needed for Layman and GeoServer to handle authorization correctly.

- Table `roles` must contain records

| name | parent |
|---------------------------------------------------------------------|--------|
| `ADMIN` | null |
| `GROUP_ADMIN` | null |
| value of [LAYMAN_GS_ROLE](./env-settings.md#LAYMAN_GS_ROLE) | null |
| `USER_<username>` of every user with [username](models.md#username) | null |

These records do not appear in [GET Roles](rest.md#get-roles). They are also not accepted in access rights.

- Table `user_roles` must contain records

| username | rolename |
|--------------------------------------------------------------------------------------------------|----------|
| `admin` | `ADMIN` |
| value of [LAYMAN_GS_USER](./env-settings.md#LAYMAN_GS_USER) | `ADMIN` |
| value of [LAYMAN_GS_USER](./env-settings.md#LAYMAN_GS_USER) | value of [LAYMAN_GS_ROLE](./env-settings.md#LAYMAN_GS_ROLE) |
| every [username](models.md#username)| `USER_<username>` |
| every [username](models.md#username)| value of [LAYMAN_GS_ROLE](./env-settings.md#LAYMAN_GS_ROLE) |

#### Business role-service records

Table `roles` may contain other records that appear in [GET Roles](rest.md#get-roles) and are accepted in access rights. Their `name` must match to regular expression `[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*` and `parent` must be null. Names `ROLE_ADMINISTRATOR`, `ROLE_GROUP_ADMIN`, `ROLE_AUTHENTICATED`, `ROLE_ANONYMOUS`, and `EVERYONE` are forbidden.

Table `user_roles` may contain other records that connects [users](models.md#user) with [roles](#role-service).

### Internal Role Service Schema
Layman provides PostgreSQL DB schema `_role_service` that can be used as the role service. The schema contain all necessary [admin records](#admin-role-service-records) and (by default) no [business records](#business-role-service-records). Business records can be added manually to tables `bussiness_roles` and `bussiness_user_roles`.

0 comments on commit ca516b4

Please sign in to comment.