diff --git a/.gitignore b/.gitignore
index b522b1da9176e59756bffe89cd4eafe0d751a23c..55fb3f0d1bc6c101704557da8f35d6e784b5ea89 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,4 +15,5 @@ build/
 src/caosdb/version.py
 
 # documentation
-_apidoc
\ No newline at end of file
+_apidoc
+*~
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aa036beccf9e7f0ab42bebd1fedc455d5ea250e1..1c9e1d8b2d2d8bfe8301bcb778acb4f1e31148e6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,10 +20,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Fixed ###
 
+* [#141](https://gitlab.indiscale.com/caosdb/src/caosdb-pylib/-/issues/141) password_method = unauthenticated not allowed by schema
+
 ### Security ###
 
 ### Documentation ###
 
+* Added curator role permissions example to code gallery
+
 ## [0.8.0] - 2022-07-12
 (Timm Fitschen)
 
diff --git a/src/caosdb/schema-pycaosdb-ini.yml b/src/caosdb/schema-pycaosdb-ini.yml
index 5dabdd89795e19a757209e03cc843776be705777..a81bf006523ab7690ee0bf9d27e0a2d57ce8c3c3 100644
--- a/src/caosdb/schema-pycaosdb-ini.yml
+++ b/src/caosdb/schema-pycaosdb-ini.yml
@@ -26,7 +26,7 @@ schema-pycaosdb-ini:
           description: The password input method defines how the password is supplied that is used for authentication with the server.
           type: string
           default: input
-          enum: [input, plain, pass, keyring]
+          enum: [input, unauthenticated, plain, pass, keyring]
         password_identifier:
           type: string
         password:
diff --git a/src/caosdb/utils/register_tests.py b/src/caosdb/utils/register_tests.py
index b15b722cecfa9a6a2b40f0bd8f6dbc1b677550cc..9d0afcbb0845e1d8d31622e8ab9926f26f7e78f6 100644
--- a/src/caosdb/utils/register_tests.py
+++ b/src/caosdb/utils/register_tests.py
@@ -26,7 +26,7 @@ from caosdb import administration as admin
 This module implements a registration procedure for integration tests which
 need a running CaosDB instance.
 
-It ensures that tests do not accidently overwrite data in real CaosDB
+It ensures that tests do not accidentally overwrite data in real CaosDB
 instances, as it checks whether the running CaosDB instance is actually the
 correct one, that
 should be used for these tests.
@@ -66,7 +66,7 @@ def _register_test():
         raise RuntimeError("Response from server for Info could not be interpreted.")
     if res > 0:
         raise RuntimeError("This instance of CaosDB contains entities already."
-                           "It must be empty in order to gegister a new test.")
+                           "It must be empty in order to register a new test.")
 
     print("Current host of CaosDB instance is: {}".format(
         db.connection.connection.get_connection()._delegate_connection.setup_fields["host"]))
diff --git a/src/doc/administration.rst b/src/doc/administration.rst
index 061acc8364d2ef62f743a20d7b9e6562baac0fc5..eab02e43a833559dc21ea7a9fa5edfaf6431facf 100644
--- a/src/doc/administration.rst
+++ b/src/doc/administration.rst
@@ -5,10 +5,12 @@ The Python script ``caosdb_admin.py`` should be used for administrative tasks.
 Call ``caosdb_admin.py --help`` to see how to use it.
 
 The most common task is to create a new user (in the CaosDB realm) and set a 
-password for the user (note that a user typically needs to be activated)::
+password for the user (note that a user typically needs to be activated):
 
-     caosdb_admin.py create_user anna
-     caosdb_admin.py set_user_password anna
-     caosdb_admin.py add_user_roles anna administration
-     caosdb_admin.py activate_user anna
+.. code:: console
+
+   $ caosdb_admin.py create_user anna
+   $ caosdb_admin.py set_user_password anna
+   $ caosdb_admin.py add_user_roles anna administration
+   $ caosdb_admin.py activate_user anna
 
diff --git a/src/doc/gallery/curator-permissions.rst b/src/doc/gallery/curator-permissions.rst
new file mode 100644
index 0000000000000000000000000000000000000000..fa6b4022b7fbc1d042ed00f265e63a2675794a21
--- /dev/null
+++ b/src/doc/gallery/curator-permissions.rst
@@ -0,0 +1,123 @@
+
+Setting permissions for a curator role
+======================================
+
+The following example shows how to create and set permissions for a ``curator``
+role that is allowed to insert, update, or delete any entity apart from a set of
+RecordTypes and properties that define a "core data model" which can only be
+altered with administration permissions.
+
+In the following, you'll learn how to
+
+1. create the ``curator`` role.
+2. configure the ``global_entity_permissions.xml`` s.th. the ``curator`` role is
+   allowed to insert, update, or delete any entity by default.
+3. use a Python script to override the above configuration for the entities in
+   the externally defined core data model.
+
+Prerequisites
+-------------
+
+This example needs some preparations regarding your CaosDB setup that have to
+(or, for the sake of simplicity, should) be done outside the actual Python
+example script.
+
+The curator role
+~~~~~~~~~~~~~~~~
+
+First, a ``curator`` role is created with a meaningful description. We'll use
+``caosdb_admin.py`` for this which leads to the following command:
+
+.. code:: console
+
+   $ caosdb_admin.py create_role "curator" "A user who is permitted to create new Records, Properties, and RecordTypes but who is not allowed to change the core data model."
+
+To actually see how this role's permissions change, we also need a user with
+this role. Assume you already have created and activated (see
+:doc:`Administration <../administration>`) a ``test_curator`` user, then
+``caosdb_admin.py`` is used again to assign it the correct role:
+
+.. code:: console
+
+   $ caosdb_admin.py add_user_roles test_curator curator
+
+.. note::
+
+   The ``test_curator`` user shouldn't have administration privileges, otherwise
+   the below changes won't have any effect.
+
+The core data model and caosdb-advanced-user-tools
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In principle, the following script works with any data model defined in a json
+or yaml file (just adapt lines 39-42 accordingly). In this example, we'll use the
+`metadata schema <https://github.com/leibniz-zmt/zmt-metadata-schema>`_ that was
+developed by J. Schmidt at the `Leibniz Centre for Tropical Marine Research
+<https://www.leibniz-zmt.de/en/>`_.
+
+Clone the schemata into the same directory containing the below script via
+
+.. code:: console
+
+   $ git clone https://github.com/leibniz-zmt/zmt-metadata-schema.git
+
+Furthermore, we'll need the `CaosDB Advanced User Tools
+<https://gitlab.com/caosdb/caosdb-advanced-user-tools>`_ for loading the
+metadata schemata from the json files, so install them via
+
+.. code:: console
+
+   $ pip install caosadvancedtools
+
+The global entity permissions file
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Users with the ``curator`` role should be able to have any permission for all
+entities by default. The exceptions for the core data model entities will be set
+with the script below. These default settings are best done via the
+``global_entities_permissions.xml`` config file (see the `server documentation
+<https://docs.indiscale.com/caosdb-server/permissions.html#how-to-set-permissions>`_). Simply
+add the following line to the file
+
+.. code:: xml
+
+   <Grant priority="true" role="curator"><Permission name="*"/></Grant>
+
+This means that, by default, all users with the ``curator`` role are **granted**
+all entity permissions (including insert, update, and delete as specified in the
+beginning) **with priority**. This ensures, that no normal user is allowed to
+overrule these permissions (since it is granted with priority), but it can still
+be denied for the core data model entities by a **deny** rule with priority. See
+the server documentation on `permission
+calculation <https://docs.indiscale.com/caosdb-server/permissions.html#permission-calculation>`_
+for more information on which permission rules can or can't be overruled.
+
+Your complete ``global_entities_permissions.xml`` might then look like
+
+.. code:: xml
+
+   <globalPermissions>
+       <Grant priority="false" role="?OWNER?"><Permission name="*"/></Grant>
+       <Grant priority="false" role="?OTHER?"><Permission name="RETRIEVE:*"/></Grant>
+       <Grant priority="false" role="?OTHER?"><Permission name="USE:*"/></Grant>
+       <Grant priority="false" role="anonymous"><Permission name="RETRIEVE:*"/></Grant>
+       <Grant priority="true" role="curator"><Permission name="*"/></Grant>
+       <Deny priority="false" role="?OTHER?"><Permission name="UPDATE:*"/></Deny>
+       <Deny priority="false" role="?OTHER?"><Permission name="DELETE"/></Deny>
+       <Deny priority="true" role="?OTHER?"><Permission name="EDIT:ACL"/></Deny>
+   </globalPermissions>
+
+.. note::
+
+   Note that you have to restart your CaosDB server after modifying the
+   ``global_entities_permissions.xml``.
+
+The code
+--------
+
+After having applied all of the above prerequisites and restarting your CaosDB
+server, execute the following code.
+
+:download:`Download full code<curator_permissions.py>`
+
+.. literalinclude:: curator_permissions.py
diff --git a/src/doc/gallery/curator_permissions.py b/src/doc/gallery/curator_permissions.py
new file mode 100644
index 0000000000000000000000000000000000000000..16b4b7f6f1bb9abfb7e191c6a1101181984bce9a
--- /dev/null
+++ b/src/doc/gallery/curator_permissions.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+# encoding: utf-8
+#
+# This file is a part of the CaosDB Project.
+#
+# Copyright (C) 2022 Indiscale GmbH <info@indiscale.com>
+# Copyright (C) 2022 Florian Spreckelsen <f.spreckelsen@indiscale.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+
+import os
+import sys
+
+import caosdb as db
+from caosadvancedtools.models.parser import parse_model_from_json_schema
+from caosdb import administration as admin
+
+CURATOR = "curator"
+
+
+def main():
+    """Set curator role permissions: Is allowed to edit all Records; is allowed
+    to create new RTs and Properties and change them, but is not allowed to
+    change anything defined in the core data model, i.e., in the schemas.
+
+    """
+    dataspace_definitions = parse_model_from_json_schema(
+        "zmt-metadata-schema/schemas/dataspace.schema.json")
+    dataset_definitions = parse_model_from_json_schema(
+        "zmt-metadata-schema/schemas/dataset.schema.json")
+
+    # Set general permissions. The curator users should be allowed to perform
+    # any transaction.
+    perms = admin._get_permissions(CURATOR)
+    general_grant_perms = [
+        "TRANSACTION:*"
+    ]
+
+    for p in general_grant_perms:
+
+        g = admin.PermissionRule(action="Grant", permission=p, priority=True)
+        d = admin.PermissionRule(action="Deny", permission=p, priority=True)
+
+        if g in perms:
+            perms.remove(g)
+        if d in perms:
+            perms.remove(d)
+        perms.add(g)
+
+    admin._set_permissions(CURATOR, permission_rules=perms)
+
+    # Deny all permissions that could change the data model ...
+    core_model_deny_permissions = [
+        "DELETE",
+        "UPDATE:*",
+        "EDIT:ACL"
+    ]
+    # ... but allow read-access and of course using the entities as parents,
+    # properties, ...
+    core_model_grant_permissions = [
+        "RETRIEVE:*",
+        "USE:*",
+    ]
+
+    # Iterate over all entities defined in the schemas and update their access control list (ACL) accordingly.
+    updates = db.Container()
+    for model in [dataspace_definitions, dataset_definitions]:
+
+        for ent in model.values():
+            if ent.name in [u.name for u in updates]:
+                # Skip entities that have been updated already
+                continue
+            # The entity needs to be retrieved with the ACL flag to update the
+            # ACL down the road
+            ent.retrieve(flags={"ACL": None})
+            for d in core_model_deny_permissions:
+                ent.deny(role=CURATOR, priority=True, permission=d)
+            ent.update_acl()
+            ent.retrieve(flags={"ACL": None})
+            for g in core_model_grant_permissions:
+                ent.grant(role=CURATOR, priority=True, permission=g)
+            updates.append(ent)
+            ent.update_acl()
+
+
+if __name__ == "__main__":
+
+    sys.exit(main())
diff --git a/src/doc/gallery/index.rst b/src/doc/gallery/index.rst
index a6ef53e4c7d1272c5dbc8c62b4d90a89591cac0f..bfba4317c3556d0692eb402f42ba3699be586d5a 100644
--- a/src/doc/gallery/index.rst
+++ b/src/doc/gallery/index.rst
@@ -14,3 +14,4 @@ This chapter collects code examples which can be immediately run against an empt
    :caption: The code examples:
 
    simulation
+   curator-permissions
diff --git a/unittests/test_configs/pycaosdb6.ini b/unittests/test_configs/pycaosdb6.ini
new file mode 100644
index 0000000000000000000000000000000000000000..3826564f043c5702385a3d093cb4ebb8d4c24cd2
--- /dev/null
+++ b/unittests/test_configs/pycaosdb6.ini
@@ -0,0 +1,4 @@
+[Connection]
+url=https://localhost:10443/
+# No username, unauthenticated connection
+password_method = unauthenticated