OAK-10069 : Best practices on how to setup access control external identities (#851)

* OAK-10069 : Best practices on how to setup access control external identities

* Update oak-doc/src/site/markdown/security/authentication/external/bestpractices.md

Co-authored-by: Jörg Hoh <joerghoh@users.noreply.github.com>

* Update oak-doc/src/site/markdown/security/authentication/external/bestpractices.md

Co-authored-by: Jörg Hoh <joerghoh@users.noreply.github.com>

* OAK-10069 : Best practices on how to setup access control external identities (review findings)

* Update oak-doc/src/site/markdown/security/authentication/external/bestpractices.md

Co-authored-by: Jörg Hoh <joerghoh@users.noreply.github.com>

---------

Co-authored-by: Jörg Hoh <joerghoh@users.noreply.github.com>
diff --git a/oak-doc/src/site/markdown/dos_and_donts.md b/oak-doc/src/site/markdown/dos_and_donts.md
index 41b32dc..fda15e0 100644
--- a/oak-doc/src/site/markdown/dos_and_donts.md
+++ b/oak-doc/src/site/markdown/dos_and_donts.md
@@ -122,6 +122,7 @@
 ```
 ## Security
 - [Best Practices for Authorization](security/authorization/bestpractices.html)
+- [Best Practices for External Authentication](security/authentication/external/bestpractices.html)
 
 ## Misc
 ### Don't use Thread.interrupt()
diff --git a/oak-doc/src/site/markdown/security/authentication/external/bestpractices.md b/oak-doc/src/site/markdown/security/authentication/external/bestpractices.md
new file mode 100644
index 0000000..55f5829
--- /dev/null
+++ b/oak-doc/src/site/markdown/security/authentication/external/bestpractices.md
@@ -0,0 +1,128 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+# Best Practices for External Authentication
+
+<!-- MACRO{toc} -->
+
+## Before you get started
+
+Before you get started make sure you are familiar with the basic concepts of JCR authentication, and its implementation in Apache Jackrabbit Oak.
+
+External authentication in Oak refers to integrating a third party identity provider like LDAP or SAML into the authentication setup optionally combining it with other built-in authentication mechanisms.
+
+## Best Practices 
+
+### JAAS Setup
+
+When combining external authentication with other built-in or custom [login modules] make sure to define a [configuration] with the optimal order and the proper [control flag] for each module to cover all cases. The order should be chosen such that optional and sufficient login modules come first. Potentially expensive authentication against a third party identity provider as well as those for rare use cases should be defined with a lower ranking. 
+
+Additional reading: https://docs.oracle.com/en/java/javase/11/security/appendix-b-jaas-login-configuration-file.html#GUID-7EB80FA5-3C16-4016-AED6-0FC619F86F8E
+
+#### Combination with Token Authentication
+
+Whenever JCR sessions created with Oak are short-lived (e.g. only lasting for a single HTTP request) authentication against an external IDP may not perform well. It is therefore recommended to use external authentication in combination with an additional authentication mechanism like e.g. the built-in [token login](../tokenmanagement.html).
+
+Make sure the token login module has [control flag] 'SUFFICIENT' and is evaluated prior to the external login that connects to the external IDP.
+
+#### Combination with Default Authentication
+
+Oak comes with a default login for user accounts stored and managed inside the JCR content repository. This also includes support for default users like 'anonymous' (guest) and 'admin' with full access to the repository. If this is desired, it is recommend to also add the [default `LoginModule`](../default.html#uid_pw) to the JAAS configuration.
+
+The optional order depends on the frequency of default vs external login: if login or impersonation against local users occurs frequently (e.g. unauthentication login with [GuestCredentials]) the default login module should have a higher ranking. However, if authentication of local users is unlikely, the external oak login should have a ranking.
+
+##### Example JAAS Configuration
+
+The following JAAS configuration is an example when running an Oak repository with external authentication in combination with Apache Sling:
+
+| Ranking | Control Flag | LoginModule Class Name |
+|---------|--------------|------------------------|
+| 300     | OPTIONAL     | org.apache.jackrabbit.oak.spi.security.authentication.GuestLoginModule |
+| 200     | SUFFICIENT   | org.apache.jackrabbit.oak.security.authentication.token.TokenLoginModule | 
+| 150     | SUFFICIENT   | org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalLoginModuleFactory |
+| 100     | SUFFICIENT   | org.apache.jackrabbit.oak.security.authentication.user.LoginModuleImpl |
+
+See [Authentication with External Login Module : Examples](externallogin_examples.html#Integration_with_Standard_Oak_Authentication_used_for_Apache_Sling) for a detailed explanation as well as alternative 
+configurations.
+
+### Synchronization of Users and Groups
+
+The external authentication module in Oak comes with the option to synchronize external identities into the content repository (see section [User and Group Synchronization](../usersync.html)).
+
+The following best practices should be followed:
+
+#### External Identity Provider as SSOT
+
+Your external identity provider should be considered the single source of truth (SSOT) for all users and groups defined and managed by it. 
+
+In contrast, the users/groups synchronized into the repository should be considered a volatile cache and ideally are immutable (i.e. only maintained by system sessions in charge of the synchronization). 
+
+The following features provided by the _oak-auth-external_ module help to prevent unintended modification of synchronized external identities:
+
+- [Dynamic Membership](defaultusersync.html#dynamic_membership): Enabling dynamic membership will result in membership information being stored in a protected property that cannot be altered using regular JCR write or Jackrabbit user management API. 
+- [Dynamic Group](defaultusersync.html#dynamic_groups): Can be used in combination with dynamic membership when the application requires group principals to also exposed through `UserManager` (and not just through `PrincipalManager` as it would be needed for permission setup). Note though that these group accounts cannot have members added (see section [Enforcing dynamic groups](defaultusersync.html#enforcing_dynamic_groups))
+- [Protecting External Identities](defaultusersync.html#protect_external_identities): The module comes with [configuration 
+ option](defaultusersync.html#configuration_principals) to protect external identities. If enabled (as warning or as full protection) a dedicated validator that will report/fail attempts to modify synchronized external identities. This will help to identify violations of the immutability contract.
+ 
+#### User Management for External Identities
+
+- Properties and membership for external identities must be managed in the external IDP. Changes made in the JCR repository using user management API will be overwritten upon the next sync.
+- Never set a password for external users to make sure uid/pw login gets authenticated against the external IDP and never against the synchronized user in the repository.
+
+#### Membership Nesting
+
+For performance reasons avoid defining unnecessary membership nesting that increase the number of indirections (see [Best Practices for Authorization](../../authorization/bestpractices.html)).
+
+#### Membership crossing IDP boundaries
+
+Introducing membership crossing IDP boundaries should be considered a trust boundary violation.
+
+If adding external identities to local groups cannot be avoided, leverage [conditional auto-membership](defaultusersync.html#configuration_automembership) or auto-membership configuration in combination with dynamic membership (see [Configuration of the DefaultSyncHandler](defaultusersync.html#configuration_sync_handler)).
+
+### Authorization for External Identities
+
+Upon repository login through external authentication the subject is populated with principals obtained from the external identity provider. 
+
+In addition, the configured auto-membership will be resolved for the external user and its external groups (see autoMembership configuration [options](defaultusersync.html#configuration_sync_handler) and section [Automatic Membership with AutoMembershipConfig](defaultusersync.html#configuration_automembership))
+
+The authenticated session will be subject to regular Oak permission evaluation as defined for the instance and described in section [Permissions](../../permission.html). 
+
+#### Access control setup
+
+Synchronized external identities (both in default and in dynamic sync mode) are exposed as principals through the [Principal Management API](../../principal.html) and can be used for access control setup as described in [Access Control Management](../../accesscontrol.html).
+
+See also section [Best Practices for Authorization](../../authorization/bestpractices.html) for recommendations.
+
+External groups get synchronized together with external users upon repository login. If you wish to defined access control setup for groups prior to the synchronization upon login the following 2 options exist:
+
+- Pre-sync external groups to make them available to the principal manager (see next section)
+- Configure [ImportMode](../../accesscontrol/default.html#configuration)=`besteffort` with the default Oak authorization setup and define access control content for principals before they exist.
+  
+#### Pre-sync of external groups
+
+The following 2 options exist to populate the repository with external group principals outside of the regular synchronization upon login:
+
+- The _oak-auth-external_ module comes with a JMX integration that allows for synchronization of external identities outside of the regular repository login. See [JMX Synchronization Tool](../usersync.html#jmx-synchronization-tool) and [SynchronizationMBean](https://jackrabbit.apache.org/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/jmx/SynchronizationMBean.html) for details. This requires the `ExternalIdentityProvider` to implement the methods required to retrieve external identities. This is the recommended way to pre-sync groups.
+- In case the `ExternalIdentityProvider` does not support user and group sync outside of the regular repository login, external identities can be created using Jackrabbit User Management API. Note: 
+    - The property `rep:externalId` is system maintained and protected and cannot be added or changed once the group has been persisted.
+    - Mistakes in defining the protected properties `rep:externalId`, `rep:authorizableId` or `rep:principalName` will result in a mismatch during authentication, sync and permission evaluation. The only way to fix such mistakes is to remove and recreate the group. Access control content associated with a wrong principal name needs to be removed separately.
+
+<!-- references -->
+[login modules]: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/javax/security/auth/spi/LoginModule.html
+[configuration]: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/javax/security/auth/login/Configuration.html
+[control flag]: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/javax/security/auth/login/AppConfigurationEntry.LoginModuleControlFlag.html
+[GuestCredentials]: https://s.apache.org/jcr-2.0-javadoc/javax/jcr/GuestCredentials.html
\ No newline at end of file
diff --git a/oak-doc/src/site/markdown/security/authentication/external/defaultusersync.md b/oak-doc/src/site/markdown/security/authentication/external/defaultusersync.md
index 8b13c8d..55141ad 100644
--- a/oak-doc/src/site/markdown/security/authentication/external/defaultusersync.md
+++ b/oak-doc/src/site/markdown/security/authentication/external/defaultusersync.md
@@ -15,12 +15,14 @@
    limitations under the License.
 -->
 
-User and Group Synchronization : The Default Implementation
+# User and Group Synchronization : The Default Implementation
 --------------------------------------------------------------------------------
 
-### Default Implementation of Sync API
+<!-- MACRO{toc} -->
 
-#### SyncManager
+## Default Implementation of Sync API
+
+### SyncManager
 
 The default implementation (`SyncManagerImpl`) is intended for use in an OSGi-base
 repository setup: it tracks all `SyncHandler` registered via OSGi.
@@ -28,20 +30,20 @@
 It can be used in non-OSGi environments by passing a `org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard`
 to the constructor.
 
-#### SyncHandler
+### SyncHandler
 
 The [DefaultSyncHandler] comes with a set of configuration options that
 allow to specify the synchronization behavior (see below). Depending on the 
 configuration it chooses between two different `SyncContext` implementations.
 
-#### SyncContext
+### SyncContext
 
 Oak provides the following implementations of the [SyncContext] interface:
 
 - [DefaultSyncContext]: base implementation that synchronizes external user and group accounts into the repository
 - [DynamicSyncContext]: derived implementation that provides special handling for external groups.
  
-##### DefaultSyncContext
+#### DefaultSyncContext
 
 All users/groups synchronized by this context will get the following properties set.
 These properties allow to run separate task for periodical update and make sure
@@ -59,7 +61,7 @@
 The [DefaultSyncContext] is exported as part of the 'basic' package space and
 may be used to provide custom implementations.
 
-##### DynamicSyncContext
+#### DynamicSyncContext
 
 Extending from the [DefaultSyncContext] this implementation that provides special 
 handling  for external groups in case the [Dynamic Group Membership](#dynamic_membership) 
@@ -70,21 +72,22 @@
 
 - `rep:externalPrincipalNames` : Optional system-maintained property related to [Dynamic Group Membership](#dynamic_membership)
 
-#### SyncResult
+### SyncResult
 
 The [DefaultSyncResultImpl] is exported as part of the 'basic' package space 
 providing a simple `SyncResult` implementation based on a status and a [DefaultSyncedIdentity].
 
 
-#### SyncedIdentity
+### SyncedIdentity
 
 The [DefaultSyncedIdentity] is exported as part of the 'basic' package space. It 
 maps the ID of a synchronized user/group account to the external identity references
 represented by [ExternalIdentityRef].
 
 
+### Dynamic Sync
 <a name="dynamic_membership"></a>
-### Dynamic Group Membership
+#### Dynamic Group Membership
 
 As of Oak 1.5.3 the default sync handler comes with an addition configuration 
 option that allows enabling dynamic group membership resolution for external users. 
@@ -95,7 +98,7 @@
 section [Dynamic Membership and Dynamic Groups](dynamic.html). 
 
 <a name="dynamic_groups"></a>
-### Dynamic Groups
+#### Dynamic Groups
 
 As of Oak 1.46.0 there exists the option to leverage [Dynamic Membership](#dynamic_membership) in combination with a 
 new `Dynamic Groups` configuration option (see also [OAK-9803]). If both options are enabled external groups will continue 
@@ -104,7 +107,7 @@
 See section [Dynamic Membership and Dynamic Groups](dynamic.html) for details and comparison.
 
 <a name="xml_import"></a>
-#### XML Import
+### XML Import
 
 The protected nature of the `rep:externalPrincipalNames` is also reflected during
 XML import of user accounts:
@@ -118,9 +121,9 @@
 will re-create the `rep:externalPrincipalNames` property.
 
 <a name="validation"></a>
-#### Validation
+### Validation
 
-##### rep:externalPrincipalNames
+#### rep:externalPrincipalNames
 
 As of Oak 1.5.3 a dedicated `Validator` implementation asserts that the protected,
 system-maintained property `rep:externalPrincipalNames` is only written by the 
@@ -140,7 +143,7 @@
 | 0072              | Property 'rep:externalPrincipalNames' requires 'rep:externalId' to be present on the Node. |
 | 0073              | Property 'rep:externalId' cannot be removed if 'rep:externalPrincipalNames' is present. |
 
-##### rep:externalId
+#### rep:externalId
 
 If protection of the `rep:externalId` property is enabled (since Oak 1.5.8) the
 validator performs the following checks:
@@ -150,7 +153,8 @@
 | 0074              | Attempt to add, modify or remove the system maintained property 'rep:externalId'. |
 | 0075              | Property 'rep:externalId' may only have a single value of type STRING. |
  
-##### Protecting synchronized external users/groups 
+<a name="protect_external_identities"></a> 
+#### Protecting synchronized external users/groups 
 
 If protection of synchronized external users/groups is enabled (since Oak 1.44.0) an additional validator is present
 which either warns upon or prevents creation, modification and removal of external identities that have been synchronized 
@@ -175,7 +179,8 @@
 | 0076 | Attempt to remove protected external identity '%s'                         |
 | 0076 | Attempt to remove node '%s' from protected external identity               |
 
-##### Enforcing dynamic groups
+<a name="enforcing_dynamic_groups"></a> 
+#### Enforcing dynamic groups
 
 If `user.dynamicMembership` is enabled together with `group.dynamicGroups` a separate validator will be present to
 make sure no members are added to the dynamic groups through regular API calls (`Group.addMember(Authorizable)` and 
@@ -196,6 +201,7 @@
 <a name="configuration"></a>
 ### Configuration
 
+<a name="configuration_sync_handler"></a>
 #### Configuration of the DefaultSyncHandler
 
 The default `SyncHandler` implementations are configured via [DefaultSyncConfig]:
@@ -219,6 +225,12 @@
 | Group 'Dynamic Groups'        | `group.dynamicGroups`         | Only takes effect in combination with `user.dynamicMembership` and will result in external groups being synced as dynamic groups. |
 | | | |
 
+Note, that the following options relate to the [dynamic sync](dynamic.html) feature:
+- `user.dynamicMembership` : Enabling dynamic membership for external users.
+- `user.enforceDynamicMembership` : If enabled together with `user.dynamicMembership` previously synced membership information will be migrated to dynamic membership upon user sync. Otherwise it takes no effect.
+- `group.dynamicGroups` : Only takes effect in combination with `user.dynamicMembership` and will result in external groups being synced as dynamic groups.
+
+<a name="configuration_automembership"></a>
 #### Automatic Membership with AutoMembershipConfig
 Since Oak 1.42.0 ([OAK-9463]) the auto-membership behavior can be extended to allow for conditional group membership 
 based on characteristics of a given synced external identity. In addition to configuration options `group.autoMembership` 
@@ -230,6 +242,7 @@
 If present the additional membership defined by the [AutoMembershipConfig], will be reflected upon default and dynamic 
 sync together with the original, 'global' auto-membership configuration.
 
+<a name="configuration_principals"></a>
 #### Configuration of the 'Apache Jackrabbit Oak External PrincipalConfiguration'
 
 Please note that the `ExternalPrincipalConfiguration` _("Apache Jackrabbit Oak External PrincipalConfiguration")_ 
diff --git a/oak-doc/src/site/markdown/security/authentication/external/dynamic.md b/oak-doc/src/site/markdown/security/authentication/external/dynamic.md
index 1be242c..f0ed493 100644
--- a/oak-doc/src/site/markdown/security/authentication/external/dynamic.md
+++ b/oak-doc/src/site/markdown/security/authentication/external/dynamic.md
@@ -15,14 +15,16 @@
    limitations under the License.
 -->
 
-User and Group Synchronization : Dynamic Membership and Dynamic Groups
+# User and Group Synchronization : Dynamic Membership and Dynamic Groups
 ----------------------------------------------------------------------
 
+<!-- MACRO{toc} -->
+
 As of Oak 1.5.3 the default sync handler comes with an additional configuration 
 option (see section [Configuration](defaultusersync.html#configuration) 
 that allows enabling dynamic group membership resolution for external users. 
 
-Enabling dynamic membership in the [DefaultSyncConfig] will change the way external
+Enabling dynamic sync options in the [DefaultSyncConfig] will change the way external
 groups are synchronized (see [OAK-4101]) and how automatic group membership 
 is being handled (see [OAK-4087]).
 
@@ -32,14 +34,14 @@
 - avoid storing/updating auto-membership which is assigned to all external users
 - ease principal resolution upon repository login
 
-See also [FAQ](faq.html#Dynamic_Sync) for frequently asked questions about thes dynamic sync.
+See also [FAQ](faq.html#Dynamic_Sync) for frequently asked questions about the dynamic sync.
 
-### SyncContext with Dynamic Membership
+## SyncContext with Dynamic Membership
 
 With the default `SyncHandler` this configuration option will show the following 
 effects:
 
-#### External Groups
+### External Groups
 
 - If enabled the handler will use an alternative [SyncContext] to synchronize external groups (`DynamicSyncContext`).
 - Instead of synchronizing membership information alongside the group accounts, this `DynamicSyncContext`
@@ -61,7 +63,7 @@
 of `ExternalIdentityProvider` needs to also implement `PrincipalNameResolver`.
 See also [OAK-5210].
 
-#### Automatic Membership
+### Automatic Membership
 
 - If enabled automatic membership assignment for existing, local groups will not longer be written to the repository
 - Instead, the `ExternalPrincipalConfiguration` _("Apache Jackrabbit Oak External PrincipalConfiguration")_ will keep 
@@ -85,9 +87,9 @@
   and reflect autoMembership for synchronized external users in the User Management API (see below).
   The same applies for the conditional auto-membership as introduced with [OAK-9463].
   
-### Effect of Dynamic Membership on other Security Modules
+## Effect of Dynamic Membership on other Security Modules
   
-#### Principal Management
+### Principal Management
 
 The dynamic (principal) membership features comes with a dedicated `PrincipalConfiguration` 
 implementation (i.e. [ExternalPrincipalConfiguration]) that is in charge of securing  
@@ -107,7 +109,7 @@
 if it can be read from any of the `rep:externalPrincipalNames` properties 
 present using a dedicated query.
 
-##### API Overview
+#### API Overview
 
 - `extUserName`       : the principal name of an external user
 - `extGroupName`      : the principal name of an external group
@@ -121,8 +123,8 @@
 | `PrincipalManager.getGroupMembership(extUserPrincipal)`  | ok           | ok                 | ok                     | Dynamic group principals include both declared external groups and configured auto-membership principals (including inherited principals).|
 | `PrincipalManager.getGroupMembership(extGroupPrincipal)` | ok           | - <sup>2</sup>     | - <sup>2,3</sup>       | <sup>2</sup> Group membership gets flattened and stored with the external user. Group-group relationship is not preserved.<br/><sup>3</sup> For dynamic groups synced into the repository the configured auto-membership principals are resolved, see also user management API below.  |
 
-#### User Management
-##### User Management without Dynamic Groups Option
+### User Management
+#### User Management without Dynamic Groups Option
 
 Unless the 'Dynamic Groups' option is set additionally, the dynamic membership option will effectively disable the
 synchronization of the external group account information into the repository's user management feature.
@@ -148,7 +150,7 @@
 `Group.isDeclaredMember`, `Group.getMembers`, `Group.getDeclaredMembers` as well as `Authorizable.memberOf`
 and `Authorizable.declaredMemberOf()`.
 
-##### User Management with Dynamic Groups Option enabled
+#### User Management with Dynamic Groups Option enabled
 
 If the 'Dynamic Groups' flag is turned on in addition, external group accounts will continue to be synchronized into the 
 repository's user management. However, membership information will not be stored together with the groups but instead will 
@@ -164,7 +166,7 @@
 equivalent Oak API operations will be prevented by a dedicated validator that is enabled as soon as the _Dynamic Groups_
 option is present together with _Dynamic Membership_.
 
-##### API Overview
+#### API Overview
 
 - `extUserId`  : the ID of a synchronized external user
 - `extGroupId` : the ID of a synchronized external group
@@ -197,7 +199,7 @@
 | `autoGroup.getDeclaredMembers()`                         | ok           | (ok) <sup>5,12</sup>| ok <sup>12</sup>      |  |
 | `autoGroup.getMembers()`                                 | ok           | (ok) <sup>5,12</sup>| ok <sup>12</sup>      |  |
 
-#### Authentication
+### Authentication
 
 The authentication setup provided by Oak is not affected by the dynamic membership 
 handling as long as the configured `LoginModule` implementations rely on the 
@@ -205,7 +207,7 @@
 _("Apache Jackrabbit Oak External PrincipalConfiguration")_ is properly registered 
 with the `SecurityProvider` (see section [Configuration](defaultusersync.html#configuration)).
 
-#### Authorization
+### Authorization
 
 The authorization modules shipped with Oak only depend on `Principal`s (and not on
 user management functionality) and are therefore not affected by the dynamic 
diff --git a/oak-doc/src/site/markdown/security/authentication/external/externallogin_examples.md b/oak-doc/src/site/markdown/security/authentication/external/externallogin_examples.md
index 2717910..3175c64 100644
--- a/oak-doc/src/site/markdown/security/authentication/external/externallogin_examples.md
+++ b/oak-doc/src/site/markdown/security/authentication/external/externallogin_examples.md
@@ -18,8 +18,92 @@
 Authentication with External Login Module : Examples
 ----------------------------------------------------
 
-- [Integration with Standard Oak Authentication](#standard)
-- [Integration with Pre-Authentication and Login Module Chain](#preauth)
+<!-- MACRO{toc} -->
+
+<a name="standard-sling"></a>
+### Integration with Standard Oak Authentication used for Apache Sling
+
+The following JAAS configuration can be used in combination with Apache Sling.
+
+#### Example JAAS Configuration
+
+      Example {
+         org.apache.jackrabbit.oak.spi.security.authentication.GuestLoginModule optional;
+         org.apache.jackrabbit.oak.security.authentication.token.TokenLoginModule sufficient;
+         org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalLoginModule sufficient
+                                  sync.handlerName="your-synchandler_name"
+                                  idp.name="your_idp_name";
+         org.apache.jackrabbit.oak.security.authentication.user.LoginModuleImpl sufficient;
+         
+       };
+
+#### Understanding the Configuration
+
+##### The LoginModule Sequence
+
+- The `GuestLoginModule` is in charge of handling unauthenticated guest login without passing [GuestCredentials].
+  In other words: if no credentials can be obtained during the login phase, an new instance of [GuestCredentials] is 
+  pushed to the shared state and this module succeeds. Due to the _optional_ flag success is not 
+  required and the authentication proceeds down the list of modules.
+  This module helps to cover non-standard guest login with `null` credentials as it is performed by 
+  Apache Sling (compatibility with Jackrabbit 1.0)
+
+- The `TokenLoginModule` is in charge of handling repository authentication 
+  request with `TokenCredentials`: 
+    - _Login Success_: If token-login succeeds the _sufficient_ flag makes sure
+    authentication does not proceed down the `LoginModule` list. This means
+    that it will not hit the `ExternalIdentityProvider` and will not re-sync
+    an external user as long as the login token is valid.
+    - _Login Failure_: If it fails (e.g. other type of `Credentials`) the authentication
+    will proceed down the `LoginModule` list.
+    - _Commit_: If the login failed the login module will test if the
+    `Credentials` passed to the login ask for generation of a new login token.
+    If this login succeeded it will populate the `Subject` with `Principal`s,
+    `Credentials` and `AuthInfo`.
+    
+    NOTE: In this setup the `TokenLoginModule` is expected to only handle
+    subsequent authentication request after having issued a login token.
+    The latter is achieved by providing `Credentials` attributes that force
+    the `TokenLoginModule` to generate a new login token in the _commit_ phase.
+    The application should then use that login toke for subsequent requests.
+  
+    See [Token Authentication and Token Management](../tokenmanagement.html) for
+    details and for a description of the default implementation.
+    
+- The `ExternalLoginModule` is in charge of handling authentication request for
+  users managed by an `ExternalIdentityProvider`.
+    - _Login Success_: If user authentication against the IDP succeeds
+      the module synchronizes the external user into the repository according
+      to the logic defined in the configure `SyncHandler`. If the user
+      has been synced before it might be updated. If and how often a user
+      gets re-synced is an implementation detail of the `SyncHandler`.
+    - _Login Failure_: If the authentication fails (e.g. wrong IDP or invalid
+      `Credentials`), the login will proceed to the `LoginModuleImpl`.
+    - _Commit_: If the login succeeded the login module will populate the 
+      `Subject` with `Principal`s, `Credentials` and `AuthInfo`.
+   
+      NOTE: if no login token is generated upon first login, any subsequent
+      login for _external_ users will end up being handled by this module 
+      (including connection to the IDP) or fail.
+  
+- The `LoginModuleImpl` is in charge of handling authentication request for
+  users managed and created through the repository's user management API;
+  i.e. users that are not defined by an `ExternalIdentityProvider`. This
+  includes built-in system users like the administrator, the guest-user
+  (aka anonymous) or `SystemUsers`. It also handles impersonation logins.
+    - _Login Success_: If regular user authentication (or impersonation) succeeds
+      the _sufficient_ flag makes sure authentication does not proceed 
+      down the `LoginModule` list i.e. omits unnecessarily trying to 
+      authenticate a local user against the external IDP.
+    - _Login Failure_: If the authentication fails (e.g. no local user that
+      could have uid/pw matching the passed `Credentials`), it will
+      continue down the `LoginModule` list. 
+    - _Commit_: If the login succeeded the login module will populate the 
+      `Subject` with `Principal`s, `Credentials` and `AuthInfo`.
+      
+      NOTE: if no login token is generated upon first login, any subsequent
+      login for _local_ users will end up being handled by this module or fail.
+     
 
 <a name="standard"></a>
 ### Integration with Standard Oak Authentication
diff --git a/oak-doc/src/site/markdown/security/authentication/externalloginmodule.md b/oak-doc/src/site/markdown/security/authentication/externalloginmodule.md
index 60a6bd6..11440b2 100644
--- a/oak-doc/src/site/markdown/security/authentication/externalloginmodule.md
+++ b/oak-doc/src/site/markdown/security/authentication/externalloginmodule.md
@@ -36,8 +36,9 @@
 * provide a transparent oak principal provider.
 * offer services for background synchronization of users and groups
 
-<a name="details"></a>
+See also [Best Practices for External Authentication](external/bestpractices.html).
 
+<a name="details"></a>
 ### Implementation Details
 The external identity and login handling is split into 3 parts:
 
diff --git a/oak-doc/src/site/markdown/security/authorization/bestpractices.md b/oak-doc/src/site/markdown/security/authorization/bestpractices.md
index 6c4ddeb..5fad4fc 100644
--- a/oak-doc/src/site/markdown/security/authorization/bestpractices.md
+++ b/oak-doc/src/site/markdown/security/authorization/bestpractices.md
@@ -158,6 +158,7 @@
 
 - If access is granted, avoid repeating the same setup down the hierarchy.
 - Avoid setup for principals with administrative access for which permission evaluation is omitted. It might even create a false sense of security.
+- Avoid redundant membership as it will impact performance of permission evaluation
 
 ### Principal by principle
 
diff --git a/oak-doc/src/site/markdown/security/overview.md b/oak-doc/src/site/markdown/security/overview.md
index 8cdabcc..e1fd787 100644
--- a/oak-doc/src/site/markdown/security/overview.md
+++ b/oak-doc/src/site/markdown/security/overview.md
@@ -37,6 +37,7 @@
      * [User and Group Synchronization](authentication/usersync.html)
      * [Identity Management](authentication/identitymanagement.html)
      * [LDAP Integration](authentication/ldap.html)
+     * [Best Practices](authentication/external/bestpractices.html)
 
 ### Authorization
 
@@ -44,6 +45,7 @@
      * [Access Control Management](accesscontrol.html)
      * [Permission Evaluation](permission.html)
      * [Combining Multiple Authorization Models](authorization/composite.html)
+     * [Best Practices](authorization/bestpractices.html)
   
 #### Access Control Management
 
diff --git a/oak-doc/src/site/markdown/security/principal.md b/oak-doc/src/site/markdown/security/principal.md
index bcde86c..cd3da47 100644
--- a/oak-doc/src/site/markdown/security/principal.md
+++ b/oak-doc/src/site/markdown/security/principal.md
@@ -21,12 +21,12 @@
 <a name="jcr_api"></a>
 ### JCR API
 
-JCR itself doesn't come with a dedicated principal management API. Nevertheless
-the specification mentions `java.security.Principal` as key feature for access 
+JCR itself doesn't come with a dedicated principal management API. Nevertheless,
+the specification mentions `java.security.Principal` as a key feature for access 
 control management but leaves the discovery of principals to the implementation 
 (see [Section 16.5.7](https://s.apache.org/jcr-2.0-spec/16_Access_Control_Management.html#16.5.7%20Principal%20Discovery)).
 
-Therefore an API for principal management has been defined as part of the
+Therefore, an API for principal management has been defined as part of the
 extensions present with Jackrabbit API.
 
 <a name="jackrabbit_api"></a>