//
// 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.
//
==== Propagation

Whenever a change is performed via REST on Realms, Users, Groups or Any Objects:

. a set of <<tasks-propagation,propagation tasks>> is generated, one for each associated external resource for which the
<<mapping,mapping>> is defined for the given <<anytype, any type>> or <<realm-provisioning, realm>>;
. the generated propagation tasks are executed, e.g. the corresponding operations (create, update or delete) are sent
out, via connectors, to the configured Identity Stores, according to the configured
<<policies-propagation,propagation policy>>, if defined; the tasks can be saved for later re-execution.

[[propagation-resources]]
[TIP]
.Which external resources?
====
Depending on the entity being created / updated / deleted, different external resources are taken into account by the
propagation process:

* *Group*: only the external resources directly assigned
* *User*: the external resources directly assigned plus the ones assigned to Groups configured for the User
* *Any Object*: the external resources directly assigned plus the ones assigned to Groups configured for the Any Object
====

[[propagation-capabilities]]
[WARNING]
.Adequate capabilities to Connectors and External Resources
====
Ensure to provide an adequate set of <<connector-instance-details,capabilities>> to underlying Connectors and
External Resources for the actual operations to perform, otherwise the Propagation Tasks will report `NOT_ATTEMPTED` as
execution status.
====

[[propagation-password]]
[TIP]
.Propagate password values
====
Password values are kept in the internal storage according to the `password.cipher.algorithm`
<<configuration-parameters, configuration parameter>>, whose value is `SHA1` by default.
`SHA1` is a hash algorithm: this means that, once stored, the cleartext value cannot be reverted any more.

During propagation, Syncope fetches all data of the given User, then prepares the attributes to propagate, according to
the provided mapping; password has a special treatment:

* if cleartext value is available (this cannot happen during <<provisioning-push>>), it is sent to the External Resource
* if `password.cipher.algorithm` is `AES` (the only supported reversible algorithm), then the ciphered password value is
 made cleartext again, and sent to the External Resource
* if the `GenerateRandomPasswordPropagationActions` is enabled, a random password value is generated
 according to the defined <<policies-password,password policy>> and sent to the External Resource
* otherwise, a `null` value is sent to the External Resource

Password values are always sent to External Resources wrapped as ConnId
http://connid.tirasa.net/apidocs/1.6/org/identityconnectors/common/security/GuardedString.html[GuardedString^] objects.
====

By default, the propagation process is controlled by the
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PriorityPropagationTaskExecutor.java[PriorityPropagationTaskExecutor^],
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/blob/4_1_X/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PriorityPropagationTaskExecutor.java[PriorityPropagationTaskExecutor^],
endif::[]
which implements the following logic:

* sort the tasks according to the related resource's _priority_, then execute sequentially
* tasks for resources with no priority are executed afterwards, concurrently
* the execution of a given set of tasks is halted (and global failure is reported) whenever the first sequential task
fails
* status and eventual error message (in case of no resource priority) can be saved for reporting, in the case where the related
external resource was configured with adequate tracing
* minimize the set of operations to be actually performed onto the Identity Store by attempting to read the external
object corresponding to the internal entity and comparing with the modifications provided

[[propagation-createorupdate]]
[WARNING]
.Create or update?
====
The minimization performed by `PriorityPropagationTaskExecutor` might lead to behaviors which look at first unexpected,
but sound perfectly understandable once explained; in particular:

* a `CREATE` propagation task might result in an effective `UPDATE` sent to the Connector +
 if preliminary read returns an external object matching the same remote key of the object requested to be created
* an `UPDATE` propagation task might result in an effective `CREATE` sent to the Connector +
 if preliminary read does not find any external object matching the remote key of the objected requested to be
updated

Please also note that this behavior is affected by the configured <<policies-propagation,propagation policy>>, if
available: in particular, whether fetching around provisioning is enabled or not.
====

Different implementations of the
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/propagation/PropagationTaskExecutor.java[PropagationTaskExecutor^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/blob/4_1_X/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/propagation/PropagationTaskExecutor.java[PropagationTaskExecutor^]
endif::[]
interface can be provided, in case the required behavior does not fit into the provided implementation.

===== PropagationActions

The propagation process can be decorated with custom logic to be invoked around task execution, by associating
external resources to one or more <<implementations,implementations>> of the
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/propagation/PropagationActions.java[PropagationActions^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/blob/4_1_X/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/propagation/PropagationActions.java[PropagationActions^]
endif::[]
interface.

Some examples are included by default, see table below.

[cols="1,2"]
|===

| 
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AzurePropagationActions.java[AzurePropagationActions^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/tree/4_1_X/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AzurePropagationActions.java[AzurePropagationActions^]
endif::[]
| Required for setup of an External Resource based on the https://connid.atlassian.net/wiki/display/BASE/Azure#Azure-Configuration[ConnId Azure connector bundle^].

| 
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DBPasswordPropagationActions.java[DBPasswordPropagationActions^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/blob/4_1_X/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DBPasswordPropagationActions.java[DBPasswordPropagationActions^]
endif::[]
| If no password value was already provided in the propagation task, sends out the internal password hash value to DBMS;
the cipher algorithm associated with the password must match the value of `Password cipher algorithm` for the 
https://connid.atlassian.net/wiki/display/BASE/Database+Table#DatabaseTable-ConfigurationProperties[ConnId DatabaseTable connector bundle^].

| 
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/GenerateRandomPasswordPropagationActions.java[GenerateRandomPasswordPropagationActions^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/tree/4_1_X/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/GenerateRandomPasswordPropagationActions.java[GenerateRandomPasswordPropagationActions^]
endif::[]
| If no password value was already provided in the propagation task, random password value is generated according to the defined <<policies-password,password policy>> and sent to the External Resource.

| 
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/GoogleAppsPropagationActions.java[GoogleAppsPropagationActions^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/tree/4_1_X/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/GoogleAppsPropagationActions.java[GoogleAppsPropagationActions^]
endif::[]
| Required for setup of an External Resource based on the https://connid.atlassian.net/wiki/display/BASE/Google+Apps#GoogleApps-Configuration[ConnId GoogleApps connector bundle^].

| 
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPMembershipPropagationActions.java[LDAPMembershipPropagationActions^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/blob/4_1_X/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPMembershipPropagationActions.java[LDAPMembershipPropagationActions^]
endif::[]
| If a User is associated with a Group in Syncope, keep the corresponding User as a member of the corresponding Group in LDAP or AD.

| 
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPPasswordPropagationActions.java[LDAPPasswordPropagationActions^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/blob/4_1_X/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/LDAPPasswordPropagationActions.java[LDAPPasswordPropagationActions^]
endif::[]
| If no password value was already provided in the propagation task, sends out the internal password hash value to LDAP;
the cipher algorithm associated with the password must match the value of `passwordHashAlgorithm` for the 
https://connid.atlassian.net/wiki/display/BASE/LDAP#LDAP-Configuration[LDAP connector bundle^].

|===
