<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~ Copyright (c) 2010-2024 Evolveum
  ~
  ~ Licensed 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.
  -->

<resource oid="8a83b1a4-be18-11e6-ae84-7301fdab1d7c"
          xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:c="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
          xmlns:t='http://prism.evolveum.com/xml/ns/public/types-3'
          xmlns:xsd="http://www.w3.org/2001/XMLSchema"
          xmlns:ri="http://midpoint.evolveum.com/xml/ns/public/resource/instance-3"
          xmlns:icfs="http://midpoint.evolveum.com/xml/ns/public/connector/icf-1/resource-schema-3"
          xmlns:icfc="http://midpoint.evolveum.com/xml/ns/public/connector/icf-1/connector-schema-3"
          xmlns:my="http://whatever.com/my"
          xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3"
          xmlns:org='http://midpoint.evolveum.com/xml/ns/public/common/org-3'
          xmlns:mr="http://prism.evolveum.com/xml/ns/public/matching-rule-3"
          xmlns:cap="http://midpoint.evolveum.com/xml/ns/public/resource/capabilities-3">

    <name>LDAP</name>

    <description>
        LDAP resource using a ConnId LDAP connector. It contains configuration
        for use with OpenLDAP servers. This sample also includes synchronization
        and correlation configuration.
        This is a sample used in the "Practical Identity Management with MidPoint"
        book, chapter 10.
    </description>

    <connectorRef type="ConnectorType">
        <filter>
            <q:text>connectorType = "com.evolveum.polygon.connector.ldap.LdapConnector"</q:text>
        </filter>
    </connectorRef>

    <connectorConfiguration
            xmlns:icfc="http://midpoint.evolveum.com/xml/ns/public/connector/icf-1/connector-schema-3"
            xmlns:icfcldap="http://midpoint.evolveum.com/xml/ns/public/connector/icf-1/bundle/com.evolveum.polygon.connector-ldap/com.evolveum.polygon.connector.ldap.LdapConnector">
        <icfc:configurationProperties>
            <icfcldap:port>389</icfcldap:port>
            <icfcldap:host>ldap</icfcldap:host>
            <icfcldap:baseContext>dc=example,dc=com</icfcldap:baseContext>
            <icfcldap:bindDn>cn=idm,ou=Administrators,dc=example,dc=com</icfcldap:bindDn>
            <icfcldap:bindPassword><t:clearValue>secret</t:clearValue></icfcldap:bindPassword>
            <icfcldap:passwordHashAlgorithm>SSHA</icfcldap:passwordHashAlgorithm>
            <icfcldap:vlvSortAttribute>uid,cn,ou,dc</icfcldap:vlvSortAttribute>
            <icfcldap:vlvSortOrderingRule>2.5.13.3</icfcldap:vlvSortOrderingRule>
            <icfcldap:operationalAttributes>memberOf</icfcldap:operationalAttributes>
            <icfcldap:operationalAttributes>createTimestamp</icfcldap:operationalAttributes>
            <icfcldap:managedAssociationPairs>"inetOrgPerson"+memberOf -# "groupOfNames"+member</icfcldap:managedAssociationPairs>
            <icfcldap:placeholderMember>cn=dummy,o=whatever</icfcldap:placeholderMember>
        </icfc:configurationProperties>
    </connectorConfiguration>

    <!-- The schema will be generated by midPoint when the resource is first used -->

    <schemaHandling>

        <objectType>
            <kind>account</kind>
            <displayName>Normal Account</displayName>
            <default>true</default>
            <delineation>
                <objectClass>inetOrgPerson</objectClass>
                <auxiliaryObjectClass>midPointPerson</auxiliaryObjectClass>
            </delineation>

            <attribute>
                <ref>dn</ref>
                <displayName>Distinguished Name</displayName>
                <limitations>
                    <minOccurs>0</minOccurs>
                    <maxOccurs>1</maxOccurs>
                </limitations>
                <outbound>
                    <source>
                        <path>$focus/name</path>
                    </source>
                    <expression>
                        <script>
                            <code>
                                basic.composeDnWithSuffix('uid', name, 'ou=people,dc=example,dc=com')
                            </code>
                        </script>
                    </expression>
                </outbound>
            </attribute>
            <attribute>
                <ref>entryUUID</ref>
                <displayName>Entry UUID</displayName>
            </attribute>
            <attribute>
                <ref>cn</ref>
                <displayName>Common Name</displayName>
                <limitations>
                    <minOccurs>0</minOccurs>
                    <maxOccurs>1</maxOccurs>
                </limitations>
                <outbound>
                    <source>
                        <path>$focus/fullName</path>
                    </source>
                </outbound>
            </attribute>
            <attribute>
                <ref>sn</ref>
                <displayName>Surname</displayName>
                <limitations>
                    <minOccurs>0</minOccurs>
                    <maxOccurs>1</maxOccurs>
                </limitations>
                <outbound>
                    <source>
                        <path>$focus/familyName</path>
                    </source>
                </outbound>
            </attribute>
            <attribute>
                <ref>givenName</ref>
                <displayName>Given Name</displayName>
                <limitations>
                    <maxOccurs>1</maxOccurs>
                </limitations>
                <outbound>
                    <source>
                        <path>$focus/givenName</path>
                    </source>
                </outbound>
            </attribute>
            <attribute>
                <ref>uid</ref>
                <displayName>Login Name</displayName>
                <limitations>
                    <maxOccurs>1</maxOccurs>
                </limitations>
                <inbound>
                    <strength>strong</strength>
                    <target>
                        <path>name</path>
                    </target>
                </inbound>
                <outbound>
                    <strength>weak</strength>
                    <source>
                        <path>$focus/name</path>
                    </source>
                </outbound>
            </attribute>
            <attribute>
                <ref>employeeNumber</ref>
                <displayName>Employee Number</displayName>
                <correlator/>
                <outbound>
                    <strength>strong</strength>
                    <source>
                        <path>$focus/personalNumber</path>
                    </source>
                </outbound>
                <inbound>
                    <target>
                        <path>$focus/personalNumber</path>
                    </target>
                    <evaluationPhases>
                        <include>beforeCorrelation</include>
                        <exclude>clockwork</exclude>
                    </evaluationPhases>
                </inbound>
            </attribute>
            <attribute>
                <ref>description</ref>
                <limitations>
                    <maxOccurs>1</maxOccurs>
                </limitations>
                <outbound>
                    <strength>weak</strength>
                    <expression>
                        <value>Created by midPoint</value>
                    </expression>
                </outbound>
            </attribute>

            <activation>
                <administrativeStatus>
                    <outbound/>
                </administrativeStatus>
            </activation>

            <credentials>
                <password>
                    <outbound/>
                </password>
            </credentials>

            <synchronization>
                <reaction>
                    <situation>linked</situation>
                    <actions>
                        <synchronize/>
                    </actions>
                </reaction>
                <reaction>
                    <situation>unlinked</situation>
                    <actions>
                        <link/>
                    </actions>
                </reaction>
                <reaction>
                    <situation>unmatched</situation>
                    <actions>
                        <deleteResourceObject/>
                    </actions>
                </reaction>
            </synchronization>

            <configuredCapabilities>
                <cap:activation>
                    <cap:status>
                        <cap:attribute>ri:midPointAccountStatus</cap:attribute>
                        <cap:enableValue></cap:enableValue>
                        <cap:enableValue>enabled</cap:enableValue>
                        <cap:disableValue>disabled</cap:disableValue>
                    </cap:status>
                </cap:activation>
            </configuredCapabilities>

        </objectType>

        <objectType>
            <kind>entitlement</kind>
            <intent>ldapgroup</intent>
            <displayName>LDAP Group</displayName>
            <default>true</default>
            <delineation>
                <objectClass>ri:groupOfNames</objectClass>
            </delineation>
            <focus>
                <type>c:RoleType</type>
                <archetypeRef oid="00000000-0000-0000-0000-000000000328" relation="org:default" type="c:ArchetypeType"/>
            </focus>
            <attribute>
                <ref>ri:cn</ref>
                <outbound>
                    <name>identifier-to-cn</name>
                    <strength>weak</strength>
                    <source>
                        <path>identifier</path>
                    </source>
                </outbound>
                <inbound>
                    <name>cn-into-identifier</name>
                    <strength>strong</strength>
                    <target>
                        <path>identifier</path>
                    </target>
                </inbound>
                <inbound>
                    <name>cn-into-name</name>
                    <strength>weak</strength>
                    <expression>
                        <script>
                            <code>"LDAP: " + input</code>
                        </script>
                    </expression>
                    <target>
                        <path>name</path>
                    </target>
                </inbound>
            </attribute>
            <attribute>
                <ref>ri:description</ref>
                <tolerant>false</tolerant>
                <outbound>
                    <name>description-to-description</name>
                    <strength>strong</strength>
                    <source>
                        <path>description</path>
                    </source>
                </outbound>
                <inbound>
                    <name>description-into-description</name>
                    <strength>strong</strength>
                    <target>
                        <path>description</path>
                    </target>
                </inbound>
            </attribute>
            <attribute>
                <ref>ri:dn</ref>
                <outbound>
                    <name>identifier-to-dn</name>
                    <strength>strong</strength>
                    <source>
                        <path>identifier</path>
                    </source>
                    <expression>
                        <script>
                            <code>basic.composeDnWithSuffix('cn', identifier,
                                'ou=groups,' + basic.getResourceIcfConfigurationPropertyValue(resource,
                                'baseContext')
                                )</code>
                        </script>
                    </expression>
                </outbound>
            </attribute>
            <correlation>
                <correlators>
                    <items>
                        <name>group-correlation-by-identifier</name>
                        <description>Use inbound mapping for identifier also for correlator</description>
                        <enabled>true</enabled>
                        <item>
                            <ref>identifier</ref>
                        </item>
                    </items>
                </correlators>
            </correlation>
            <synchronization>
                <reaction>
                    <name>unlinked-link</name>
                    <situation>unlinked</situation>
                    <actions>
                        <link/>
                    </actions>
                </reaction>
                <reaction>
                    <name>linked-synchronize</name>
                    <situation>linked</situation>
                    <actions>
                        <synchronize/>
                    </actions>
                </reaction>
                <reaction>
                    <name>unmatched-import</name>
                    <situation>unmatched</situation>
                    <channel>http://midpoint.evolveum.com/xml/ns/public/common/channels-3#import</channel>
                    <actions>
                        <addFocus/>
                    </actions>
                </reaction>
                <reaction>
                    <name>deleted-synchronize</name>
                    <situation>deleted</situation>
                    <actions>
                        <synchronize/>
                    </actions>
                </reaction>
            </synchronization>
        </objectType>

        <objectType>
            <kind>generic</kind>
            <intent>ou</intent>
            <displayName>Organizational Unit</displayName>
            <delineation>
                <objectClass>organizationalUnit</objectClass>
            </delineation>

            <attribute>
                <ref>dn</ref>
                <displayName>Distinguished Name</displayName>
                <limitations>
                    <minOccurs>0</minOccurs>
                    <maxOccurs>1</maxOccurs>
                </limitations>
                <outbound>
                    <name>ldap-ou-dn</name>
                    <trace>true</trace>
                    <source>
                        <path>$focus/name</path>
                    </source>
                    <expression>
                        <script>
                            <code>
                                import javax.naming.ldap.Rdn
                                import javax.naming.ldap.LdapName

                                // We will collect names of the org units in the orgpath list
                                // We cannot add them to dn yet as we need their order to be reversed
                                def orgpath = []
                                def node = focus
                                while (true) {
                                log.debug("processing node {}", node)
                                orgpath.add(node.displayName.orig)
                                if (node.parentOrgRef == null || node.parentOrgRef.isEmpty()) {
                                break
                                } else {
                                node = midpoint.resolveReference(node.parentOrgRef[0])
                                }
                                }

                                log.debug("orgpath={}", orgpath)
                                def dn = new LdapName('ou=org,dc=example,dc=com')
                                orgpath.reverse().each { ouname -> dn.add(new Rdn('ou',ouname)) }
                                return dn.toString()
                            </code>
                        </script>
                    </expression>
                </outbound>
            </attribute>
            <attribute>
                <ref>ou</ref>
                <limitations>
                    <maxOccurs>1</maxOccurs>
                </limitations>
                <outbound>
                    <source>
                        <path>$focus/displayName</path>
                    </source>
                </outbound>
            </attribute>

        </objectType>

        <associationType>
            <name>ldapgroup-association</name>
            <displayName>LDAP Group Association</displayName>
            <description>Association for LDAP groups (under ou=groups)</description>
            <subject>
                <objectType>
                    <kind>account</kind>
                    <intent>default</intent>
                </objectType>
                <association>
                    <ref>ldapgroup</ref>
                    <sourceAttributeRef>ri:group</sourceAttributeRef>
                    <outbound>
                        <name>role-assignments-to-ldap-group-membership</name>
                        <strength>strong</strength>
                        <expression>
                            <associationConstruction xsi:type="c:AssociationConstructionExpressionEvaluatorType">
                                <objectRef>
                                    <ref>ri:group</ref>
                                    <mapping>
                                        <name>associationFromLink</name>
                                        <strength>strong</strength>
                                        <expression>
                                            <associationFromLink/>
                                        </expression>
                                    </mapping>
                                </objectRef>
                            </associationConstruction>
                        </expression>
                    </outbound>
                </association>
            </subject>
            <object>
                <objectType>
                    <kind>entitlement</kind>
                    <intent>ldapgroup</intent>
                </objectType>
            </object>
        </associationType>


    </schemaHandling>

</resource>
