//
// 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.
//
=== External Resources

****
Connector Bundles:: The components able to connect to Identity Stores; not specifically bound to Apache Syncope, 
as they are part of the http://connid.tirasa.net[ConnId^] project.
Connector Instances:: Instances of connector bundles, obtained by assigning values to the defined configuration 
properties. For instance, there is only a single `DatabaseTable` (the bundle) that can be instantiated
several times, for example if there is a need to connect to different databases.
External Resources:: Meant to encapsulate all information about how Apache Syncope will use connector instances for 
provisioning. For each entity supported by the related connector bundle (user, group, printer, services, ...),
<<mapping,mapping>> information can be specified.
****

==== Connector Bundles

Several Connector Bundles come included with Apache Syncope:

* https://connid.atlassian.net/wiki/pages/viewpage.action?pageId=360482[Active Directory^]
* https://connid.atlassian.net/wiki/display/BASE/Azure[Azure^]
* https://connid.atlassian.net/wiki/display/BASE/CMD[CMD  ^]
* https://connid.atlassian.net/wiki/display/BASE/CSV+Directory[CSV Directory^]
* https://connid.atlassian.net/wiki/display/BASE/Database[Database^]
* https://connid.atlassian.net/wiki/display/BASE/Google+Apps[Google Apps^]
* https://connid.atlassian.net/wiki/display/BASE/Kafka[Apache Kafka^]
* https://connid.atlassian.net/wiki/display/BASE/LDAP[LDAP^]
* https://connid.atlassian.net/wiki/display/BASE/Okta[Okta^]
* https://connid.atlassian.net/wiki/display/BASE/REST[Scripted REST^]
* https://connid.atlassian.net/wiki/display/BASE/ServiceNow[ServiceNow^]
* https://connid.atlassian.net/wiki/display/BASE/SCIM[SCIM^]
* https://connid.atlassian.net/wiki/display/BASE/SOAP[SOAP^]

More Connector Bundles can be <<install-connector-bundles,installed>>, if needed.

==== Connector Instance details

When defining a connector instance, the following information must be provided:

* administration realm - the <<realms,Realm>> under which administrators need to own <<entitlements,entitlements>> in
order to be allowed to manage this connector and all related external resources
* connector bundle - one of the several
https://github.com/Tirasa/ConnId/blob/4_1_X/README.md#available-connectors[already available^], or some to be
https://connid.atlassian.net/wiki/display/BASE/Create+new+connector[made from scratch^], in order to fulfill specific
requirements
* pooling information
* configuration - depending on the selected bundle, these are properties with configuration values: for example,
with https://connid.atlassian.net/wiki/display/BASE/LDAP#LDAP-Configuration[LDAP^] this means host, port, bind DN,
object classes while with
https://connid.atlassian.net/wiki/display/BASE/Database+Table#DatabaseTable-ConfigurationProperties[DBMS^] it would 
be JDBC URL, table name, etc.
* capabilities - define what operations are allowed on this connector: during <<provisioning,provisioning>>, if a
certain operation is invoked but the corresponding capability is not set on the related connector instance, no actual
action is performed on the underlying connector; the capabilities are:
** `AUTHENTICATE` - consent to <<pass-through-authentication, pass-through authentication>>
** `CREATE` - create objects on the underlying connector
** `UPDATE` - update objects on the underlying connector
** `DELETE` - delete objects on the underlying connector
** `SEARCH` - search / read objects from the underlying connector; used during <<provisioning-pull,pull>> with 
`FULL RECONCILIATION` or `FILTERED RECONCILIATION` <<pull-mode,mode>>
** `SYNC` - synchronize objects from the underlying connector; used during <<provisioning-pull,pull>> with 
`INCREMENTAL` <<pull-mode,mode>> 
** `LIVE_SYNC` - synchronize objects by subscribing to queue systems; used during <<provisioning-livesync,live sync>>

[TIP]
.Configuration and capability override
====
Capabilities and individual configuration properties can be set for _override_: in this case, all the external resources
using the given connector instance will have the chance to override some configuration values, or the capabilities set.

This can be useful when the same connector instance is shared among different resources, with little difference in the
required configuration or capabilities.
====

==== External Resource details

Given a selected connector instance, the following information is required to define an external resource:

* priority - integer value, in use by the default <<propagation,propagation task executor>>
* propagation actions - which <<propagationactions,actions>> shall be executed during propagation
* trace levels - control how much tracing (including logs and execution details) shall be carried over during
<<propagation,propagation>>, <<provisioning-pull,pull>>, <<provisioning-livesync,live sync>> and
<<provisioning-push,push>>
* <<connector-instance-details,configuration>>
* <<connector-instance-details,capabilities>>
* <<policies-account,account policy>> to enforce on Users, Groups and Any Objects assigned to
this external resource
* <<policies-password,password policy>> to enforce on Users, Groups and Any Objects assigned to
this external resource
* <<policies-propagation,propagation policy>> to apply during <<propagation,propagation>> on this external resource
* <<policies-inbound,inbound policy>> to apply during <<provisioning-pull,pull>> or
<<provisioning-livesync,live sync>> on this external resource
* <<policies-push,push policy>> to apply during <<provisioning-push,push>> on this external resource

==== Mapping

The mapping between internal and external data is of crucial importance when
configuring an external resource. Such information, in fact, plays a key role for <<provisioning,provisioning>>.

[.text-center]
image::mapping.png[title="Sample mapping",alt="Sample mapping"]

For each of the <<anytype,any types>> supported by the underlying connector, a different mapping is provided.

A mapping is essentially a collection of _mapping items_ describing the correspondence between an user / group / any
object attribute and its counterpart on the Identity Store represented by the current external resource. Each item
specifies:

* internal attribute - the <<schema, schema>> acting as the source or destination of provisioning operations; it must be
specified by an expression matching one of the following models:
** `schema` - resolves to the attribute for the given `schema`, owned by the mapped entity (user, group, any object)
** `groups[name].schema` - resolves to the attribute for the given `schema`, owned by the group with name
`name`
** `users[username].schema` - resolves to the attribute for the given `schema`, owned by the user with username
`username`
** `anyObjects[name].schema` - resolves to the attribute for the given `schema`, owned by the any object with
name `name`
** `memberships[name].schema` - resolves to the attribute for the given `schema`, owned by the membership, of group
with name `name`, of the mapped entity (user, any object), if such a membership exists
** `relationships[type][name].schema` - resolves to the attribute for the given `schema`, owned by the relationship, of
type `type` with any object with name `name`, of the mapped entity (user, group, any object), if such a relationship
exists
* external attribute - the name of the attribute on the Identity Store
* transformers - <<jexl,JEXL>> expression or Java class implementing
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/ItemTransformer.java[ItemTransformer^]
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/data/ItemTransformer.java[ItemTransformer^]
endif::[]
; the purpose is to transform values before they are sent to or received from the underlying connector
* mandatory condition - <<jexl,JEXL>> expression indicating whether values for this mapping item must be necessarily
available or not; compared to a simple boolean value, such condition allows complex statements to be expressed such as
'be mandatory only if this other attribute value is above 14', and so on
* remote key flag - should this item be considered as the key value on the Identity Store, if no
<<inbound-correlation-rules,inbound>> or <<push-correlation-rules,push>> correlation rules are applicable?
* password flag (Users only) - should this item be treated as the password value?
* purpose - should this item be considered for <<propagation,propagation>> / <<provisioning-push,push>>,
<<provisioning-pull,pull>>, both or none? 

Besides the items documented above, some more data needs to be specified for a complete mapping:

* which
http://connid.tirasa.net/apidocs/1.6/org/identityconnectors/framework/common/objects/ObjectClass.html[object class^]
shall be used during communication with the Identity Store; predefined are `\\__ACCOUNT__` for Users and 
`\\__GROUP__` for Groups
* whether matches between user / group / any object's attribute values and their counterparts on the Identity Store
should be performed in a case-sensitive fashion or not
* which schema shall be used to hold values for identifiers generated upon create by the Identity Store - required by
some cloud providers not accepting provided values as unique references
* the model for generating the DN (distinguished name) values - only required by some connector bundles as
https://connid.atlassian.net/wiki/display/BASE/LDAP[LDAP^] and
https://connid.atlassian.net/wiki/pages/viewpage.action?pageId=360482[Active Directory^]

.Mapping items
====
The following mapping item binds the mandatory internal `name` schema with the external attribute `cn` for both 
propagation / push and pull.

[source,json]
----
{
  "key": "a2bf43c8-74cb-4250-92cf-fb8889409ac1",
  "intAttrName": "name",
  "extAttrName": "cn",
  "connObjectKey": true,
  "password": false,
  "mandatoryCondition": "true",
  "purpose": "BOTH"
}
----

The following mapping item binds the optional internal `aLong` schema for the membership of the `additional` group
with the external attribute `age` for propagation / push only; in addition, it specifies a JEXL expression which appends `.0`
to the selected `aLong` value before sending it out to the underlying connector.

[source,json]
----
{
  "key": "9dde8bd5-f158-499e-9d81-3d7fcf9ea1e8",
  "intAttrName": "memberships[additional].aLong",
  "extAttrName": "age",
  "connObjectKey": false,
  "password": false,
  "mandatoryCondition": "false",
  "purpose": "PROPAGATION",
  "propagationJEXLTransformer": "value + '.0'"
}
----
====

[[object-link-realms-hierarchy]]
[TIP]
.Object link and Realms hierarchy
====
When Object link is applicable - typically with LDAP or Active Directory, as said - the need may arise to map the Realms
hierarchy into nested structures, as
https://en.wikipedia.org/wiki/Organizational_unit_(computing)[Organizational Units^].

In such cases, the following JEXL expressions can be set for Object link (assuming `o=isp` is the root suffix), for
example, which leverage the `syncope:fullPath2Dn()` custom JEXL function:

* Realms: `syncope:fullPath2Dn(fullPath, 'ou') + ',o=isp'`
* Users: `'uid=' + name + syncope:fullPath2Dn(realm, 'ou', ',') + ',o=isp'`
* Groups: `'cn=' + name + syncope:fullPath2Dn(realm, 'ou', ',') + ',o=isp'`
====

==== Linked Accounts

Sometimes the information provided by the <<mapping,mapping>> is not enough to define a one-to-one correspondence
between Users / Groups / Any Objects and objects on External Resources.

There can be many reasons for this situation, including existence of so-called _service accounts_ (typical with LDAP or
Active Directory), or simply the uncomfortable reality that system integrators keep encountering when legacy systems
are to be enrolled into a brand new IAM system.

Users can have, on a given External Resource with `USER` mapping defined:

. zero or one _mapped account_ +
if the External Resource is assigned either directly or via Group membership.
. zero or more _linked accounts_ +
as internal representation of objects on the External Resource, defined in terms of username, password and / or plain
attribute values override, with reference to the owning User.

Linked Accounts are propagated alongside with owning User - following the existing
<<push-correlation-rules,push correation rule>> if available - and pulled according to the given
<<inbound-correlation-rules,inbound correation rule>>, if present.

[.text-center]
image::linked_accounts.png[title="Linked Accounts",alt="Linked Accounts"]
