[midPoint] My approach to FreeIPA server using LDAP Connector

Wojciech Staszewski wojciech.staszewski at diagnostyka.pl
Thu Mar 26 17:31:54 CET 2020


My approach to FreeIPA server using LDAP Connector

Assumptions:

- FreeIPA v4.6.x (or maybe newer),
- midPoint v3.9 or newer,
- LDAP Connector v2.0 or newer,
- Most important: Manage IPA users and group membership only.

So, for those who don't know what FreeIPA (or IPA) server is: It is NOT
a *free beer*! :(
Link: https://www.freeipa.org/

FreeIPA is a bunch of Open Source blocks stuck together, but the most
important for us is LDAP, a 389-ds in particular, hidden under the mask.
Another important piece is the Kerberos.

Therefore the first thoughts is to use LDAP Connector. Well, there is
dedicated IPA connector, but is dead I think, or at least its
development is stalled long time ago.

The challenge:

- FreeIPA user account schema contains A LOT of ObjectClasses. Newly
created IPA account has 14 ObjectClasses:

objectClass: inetOrgPerson
objectClass: ipaObject
objectClass: mepManagedEntry
objectClass: posixGroup
objectClass: top
objectClass: inetuser
objectClass: ipaNTUserAttrs
objectClass: ipaObject
objectClass: ipaSshGroupOfPubKeys
objectClass: ipaSshUser
objectClass: krbPrincipalAux
objectClass: krbTicketPolicyAux
objectClass: mepOriginEntry
objectClass: posixAccount

- LDAP Connector doesn't like many object classes. Why?, you may ask...

Example: ipaNTUserAttrs ObjectClass REQUIRES some attributes, for
instance: ipaNTSecurityIdentifier provided in the format below:
S-1-5-21-17112102435-2119056689-2123461762-1015
The last part: "1015" is an incremental number, everything before is
constant.
The attribute value must be compound, we have constant first part and
calculate next free number for the last part, so we have to read the max
value from LDAP and increase it by 1.
This value MUST be known at the moment of account creation. The DNA
plugin is good for simple tasks, such POSIX UID and GID calculation, but
this is something we have to calculate ourselves.

There is a lot of problems like that.
I tried to configure the LDAP resource to set the "inetOrgPerson" as
default ObjectClass and all the rest as auxiliary object classes, and I
failed because of so many different errors.

Working solution:

- The LDAP account has only one ObjectClass defined in midPoint Schema
Handling.
  All the rest is made using "scripting" functionality of the connector
AFTER "create account" operation.

Problem:
If the account is created, and THEN its schema is extended, some requied
attributes are still missing,
for example "krbExtraData" and "krbPrincipalKey" which are binary data
created during password change.
But the password is already set.

So creation of an LDAP account for IPA must be done in 3 steps:
1. create LDAP account with inetOrgPerson ObjectClass only,
2. extend the account schema - add missing ObjectClasses and all
required attributes (scripting functionality),
3. set the password again for the missing Kerberos data (scripting
functionality).

The account created this way works good, it is visible in FreeIPA User
Interface, we can login to our Linux boxes using this account, Kerberos
tickets work OK.

MidPoint part:

1) Resource XML

Almost everything is standard for common LDAP resource, schema handling,
mappings, etc. - nothing really sophisticated.
These are some the parts worth mentioning:

<icfc:configurationProperties>
            <objectClassesToSynchronize>top</objectClassesToSynchronize>
            <objectClassesToSynchronize>person</objectClassesToSynchronize>
           
<objectClassesToSynchronize>organizationalPerson</objectClassesToSynchronize>
           
<objectClassesToSynchronize>inetUser</objectClassesToSynchronize>
           
<objectClassesToSynchronize>inetOrgPerson</objectClassesToSynchronize>
</icfc:configurationProperties>

<schema>
        <generationConstraints>
            <generateObjectClass>ri:top</generateObjectClass>
            <generateObjectClass>ri:person</generateObjectClass>
           
<generateObjectClass>ri:organizationalPerson</generateObjectClass>
            <generateObjectClass>ri:inetUser</generateObjectClass>
            <generateObjectClass>ri:inetOrgPerson</generateObjectClass>
            <generateObjectClass>ri:ipaNTUserAttrs</generateObjectClass>
            <generateObjectClass>ri:ipaObject</generateObjectClass>
           
<generateObjectClass>ri:ipaSshGroupOfPubKeys</generateObjectClass>
            <generateObjectClass>ri:ipaSshUser</generateObjectClass>
            <generateObjectClass>ri:krbPrincipalAux</generateObjectClass>
            <generateObjectClass>ri:krbTicketPolicyAux</generateObjectClass>
            <generateObjectClass>ri:mepOriginEntry</generateObjectClass>
            <generateObjectClass>ri:posixAccount</generateObjectClass>
            <generateObjectClass>ri:groupOfNames</generateObjectClass>
            <generateObjectClass>ri:ipaNTGroupAttrs</generateObjectClass>
            <generateObjectClass>ri:ipaUserGroup</generateObjectClass>
            <generateObjectClass>ri:nestedGroup</generateObjectClass>
            <generateObjectClass>ri:posixGroup</generateObjectClass>
            <generateObjectClass>ri:ipaHostGroup</generateObjectClass>
            <generateObjectClass>ri:ipaPermission</generateObjectClass>
        </generationConstraints>
</schema>

<schemaHandling>
            <!-- Allmost all attributes require "explicit"
fetchStrategy!!! -->
            <...>
            <fetchStrategy>explicit</fetchStrategy>
            </...>
</schemaHandling>

<scripts>
        <script>
            <host>connector</host>
            <language>Groovy</language>
            <argument>
                <name>username</name>
                <c:path
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="t:ItemPathType">$focus/name</c:path>
            </argument>
            <argument>
                <name>pass</name>
                <c:path
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="t:ItemPathType">$focus/credentials/password/value</c:path>
            </argument>
            <code>
               println "/opt/midpoint/scripts/freeipa/after_add.sh
$username $pass".execute().text</code>
            <operation>add</operation>
            <order>after</order>
        </script>
</scripts>

2) The Bash script:

#!/bin/bash

server='ipaserver.ipa.domain.ltd'
user='cn=Directory Manager'
password='LDAP PASSWORD'
basedn='dc=ipa,dc=domain,dc=ltd'
userid=$1
pass=$2

#last value for ipaNTSecurityIdentifier
declare i ipaNTSecurityIdentifier=`ldapsearch -H ldap://$server -x -w
$password -D "$user" -b "$basedn" '(objectClass=inetOrgPerson)'
ipaNTSecurityIdentifier|grep ipaNTSecurityIdentifier|rev|cut -d "-" -f
1|rev|sort|tail -1`
nextNTSecurityIdentifier=S-1-5-21-1453210229-2669001626-2403961664-$(($ipaNTSecurityIdentifier+1))

#last UID i GID - Posix
declare i olduid=`ldapsearch -H ldap://$server -x -w $password -D
"$user" -b "$basedn" '(objectClass=inetOrgPerson)' uidNumber|grep
uidNumber|cut -d " " -f 2|tail -1`
NEWUID=$(($olduid+1))
declare i oldgid=`ldapsearch -H ldap://$server -x -w $password -D
"$user" -b "$basedn" '(objectClass=inetOrgPerson)' gidNumber|grep
gidNumber|cut -d " " -f 2|tail -1`
NEWGID=$(($oldgid+1))

cat > /tmp/ipa_add_group_$userid.ldif <<EOF
dn: cn=$userid,cn=groups,cn=accounts,$basedn
objectClass: ipaObject
objectClass: mepManagedEntry
objectClass: posixGroup
objectClass: top
cn: $userid
gidNumber: $NEWGID
description: User private group for $userid
mepManagedBy: uid=$userid,cn=users,cn=accounts,$basedn
EOF

/usr/bin/ldapmodify -h $server -x -w $password -D "$user" -a -f
/tmp/ipa_add_group_$userid.ldif



cat > /tmp/ipa_add_$userid.ldif <<EOF
dn: uid=$userid,cn=users,cn=accounts,$basedn
changetype: modify
add: objectClass
objectClass: inetuser
-
add: objectClass
objectClass: ipaNTUserAttrs
-
add: objectClass
objectClass: ipaObject
-
add: objectClass
objectClass: ipaSshGroupOfPubKeys
-
add: objectClass
objectClass: ipaSshUser
-
add: objectClass
objectClass: krbPrincipalAux
-
add: objectClass
objectClass: krbTicketPolicyAux
-
add: objectClass
objectClass: mepOriginEntry
-
add: objectClass
objectClass: posixAccount
-
add: homeDirectory
homeDirectory: /home/$userid
-
add: loginshell
loginshell: /bin/bash
-
add: ipaNTSecurityIdentifier
ipaNTSecurityIdentifier: $nextNTSecurityIdentifier
-
add: uidNumber
uidNumber: $NEWUID
-
add: gidNumber
gidNumber: $NEWGID
-
add: krbCanonicalName
krbCanonicalName: $userid at IPA.DOMAIN.LTD
-
add: krbPrincipalName
krbPrincipalName: $userid at IPA.DOMAIN.LTD
-
add: preferredLanguage
preferredLanguage: YourLangHere
-
add: gecos
gecos: $userid
-
add: mepManagedEntry
mepManagedEntry: cn=$userid,cn=groups,cn=accounts,$basedn
EOF

/usr/bin/ldapmodify -h $server -x -w $password -c -D "$user" -f
/tmp/ipa_add_$userid.ldif

# Change password once again!
cat > /tmp/ipa_password_$userid.ldif <<EOF
dn: uid=$userid,cn=users,cn=accounts,$basedn
changetype: modify
replace: userPassword
userPassword: $pass
EOF

/usr/bin/ldapmodify -h $server -x -w $password -c -D "$user" -f
/tmp/ipa_password_$userid.ldif

rm -f /tmp/ipa_add_$userid.ldif
rm -f /tmp/ipa_add_group_$userid.ldif
rm -f /tmp/ipa_ipausers_$userid.ldif
rm -f /tmp/ipa_password_$userid.ldif

##########
If you know the better way, please let me know.
Best Regards!
WS

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.evolveum.com/pipermail/midpoint/attachments/20200326/c194e5f8/attachment.htm>


More information about the midPoint mailing list