Alfresco 5 – Zimbra 8


How to link Alfresco 5 to a Zimra 8.6 LDAP.

First set your authentication_chain and sync properties in

./tomcat/shared/classes/alfresco-global.properties

Replace all the bold domain/password stuff with your own of course, and use the admin account of zimbra to connect into the OpenLdap part.

Like so:

### Use Alfresco authentication for admin accounts and LDAP for users ###
authentication.chain=alfrescoNtlm1:alfrescoNtlm,ldap1:ldap
## For DEV, set synchronizeChangesOnly to false for FULL SYNC
synchronization.synchronizeChangesOnly= true 
## Set up regular synchronization with the LDAP server ##
synchronization.syncWhenMissingPeopleLogIn=true
synchronization.syncOnStartup=true
synchronization.import.cron=0 */15 * * * ?

Then create an ldap-authentication.properties File in:

./tomcat/shared/classes/alfresco/extension/subsystems/Authentication/ldap/ldap1

# LDAP Settings for OpenLDAP sync and auth

ldap.authentication.active=true
ldap.authentication.allowGuestLogin=false
ldap.authentication.userNameFormat=uid=%s,ou=people,dc=integrative,dc=it

# The LDAP context factory to use
#ldap.authentication.java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory

# The URL to connect to the LDAP server 
ldap.authentication.java.naming.provider.url=ldap://1.2.3.4:389

# The authentication mechanism to use for password validation
ldap.authentication.java.naming.security.authentication=simple

# Escape commas entered by the user at bind time Useful when using simple authentication and the CN is part of the DN and contains commas

ldap.authentication.escapeCommasInBind=false
ldap.authentication.escapeCommasInUid=false

# Comma separated list of user names who should be considered administrators by default
ldap.authentication.defaultAdministratorUserNames=admin

# Enable FTP authentication using LDAP
ldap.authentication.authenticateFTP=true

ldap.synchronization.active=true
ldap.synchronization.java.naming.security.authentication=simple
ldap.synchronization.java.naming.security.principal=uid=admin,ou=people,dc=root,dc=domain
ldap.synchronization.java.naming.security.credentials=yourpassword

ldap.synchronization.queryBatchSize=50
ldap.synchronization.attributeBatchSize=0

# The query to select all objects that represent the groups to import.

ldap.synchronization.groupQuery=(objectclass\=zimbraDistributionList)
ldap.synchronization.groupDifferentialQuery=(&(objectclass\=zimbraDistributionList)(!(modifyTimestamp< \={0})))
ldap.synchronization.groupSearchBase=ou\=people,dc\=integrative,dc\=it

ldap.synchronization.personQuery=(objectClass\=organizationalPerson)
ldap.synchronization.personDifferentialQuery=(&(objectclass\=organizationalPerson)(!(modifyTimestamp<\={0})))
ldap.synchronization.userSearchBase=ou\=people,dc\=integrative,dc\=it

# The name of the operational attribute recording the last update time for a group or user.
ldap.synchronization.personType=organizationalPerson
ldap.synchronization.modifyTimestampAttributeName=modifyTimestamp
ldap.synchronization.timestampFormat=yyyyMMddHHmmss'Z'
ldap.synchronization.userIdAttributeName=uid
ldap.synchronization.userFirstNameAttributeName=givenName
ldap.synchronization.userLastNameAttributeName=sn
ldap.synchronization.userEmailAttributeName=mail
ldap.synchronization.userOrganizationalIdAttributeName=ou
ldap.synchronization.defaultHomeFolderProvider=userHomesHomeFolderProvider

ldap.synchronization.groupIdAttributeName=mail
ldap.synchronization.groupDisplayNameAttributeName=mail
ldap.synchronization.groupType=zimbraDistributionList
ldap.synchronization.personType=zimbraMailRecipient
ldap.synchronization.groupMemberAttributeName=zimbraMailForwardingAddress

ldap.synchronization.enableProgressEstimation=true
ldap.authentication.java.naming.read.timeout=0

That;s all, reload or reboot and log in

Alfresco 5.0.d + OpenLdap


Can’t believe I once hired an Indy IT mercenary to configure this for MS/AD, sad really. Anyways was bored today and had some time so dug up my DEV server for Alfresco and found it was still using an internal database for authentication. So I took the trouble of configuring it to use the OpenLdap server we now use for all Authentications down here.

So how to get to it, firstly out Alfresco sits in /opt/alfresco (that might be different for you) from here make a folder for the ldap class like so:

mkdir -P /opt/alfresco/tomcat/shared/classes/alfresco/extension/subsystems/Authentication/ldap/ldap1

Now if you want to go from a template get the 5.0.d binary from GitHub and extract the ldap-authentication.properties to work on, like so:

wget https://github.com/Alfresco/community-edition/archive/V5.0.d.tar.gz
 tar -zxvf V5.0.d.tar.gz -C ~/tmp --wildcards --no-anchored 'ldap-authentication.properties'
 find tmp -type f -exec mv -i {} . \;
You can also just copy and paste this below to modify to your liking
 
 # LDAP Settings for OpenLDAP sync and auth
 ldap.authentication.active=true
 ldap.authentication.allowGuestLogin=false
 ldap.authentication.userNameFormat=uid=%s,ou=users,dc=integrative,dc=it
 # The LDAP context factory to use
 #ldap.authentication.java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
 # The URL to connect to the LDAP server
 ldap.authentication.java.naming.provider.url=ldap://ldap.legal-it.net:389
 # The authentication mechanism to use for password validation
 ldap.authentication.java.naming.security.authentication=simple
 # Escape commas entered by the user at bind time Useful when using simple authentication and the CN is part of the DN and contains commas
 ldap.authentication.escapeCommasInBind=false
 ldap.authentication.escapeCommasInUid=false
 # Comma separated list of user names who should be considered administrators by default
 ldap.authentication.defaultAdministratorUserNames=admin
 # Enable FTP authentication using LDAP
 ldap.authentication.authenticateFTP=true
 ldap.synchronization.active=true
 ldap.synchronization.java.naming.security.authentication=simple
 ldap.synchronization.java.naming.security.principal=cn\=admin,dc\=integrative,dc\=it
 ldap.synchronization.java.naming.security.credentials=supersecretpassword
 ldap.synchronization.queryBatchSize=50
 ldap.synchronization.attributeBatchSize=0
 # The query to select all objects that represent the groups to import.
 ldap.synchronization.groupSearchBase=ou\=groups,dc\=integrative,dc\=it
 ldap.synchronization.groupQuery=(objectclass\=groupOfNames)
 ldap.synchronization.groupDifferentialQuery=(&(objectclass\==groupOfNames)(!(modifyTimestamp<\={0})))
 ldap.synchronization.userSearchBase=ou\=users,dc\=integrative,dc\=it
 ldap.synchronization.personQuery=(objectclass\=inetOrgPerson)
 ldap.synchronization.personDifferentialQuery=(&(objectclass\=inetOrgPerson)(!(modifyTimestamp<\={0})))
 # The name of the operational attribute recording the last update time for a group or user.
 ldap.synchronization.modifyTimestampAttributeName=modifyTimestamp
 ldap.synchronization.timestampFormat=yyyyMMddHHmmss'Z'
 ldap.synchronization.userIdAttributeName=uid
 ldap.synchronization.userFirstNameAttributeName=givenName
 ldap.synchronization.userLastNameAttributeName=sn
 ldap.synchronization.userEmailAttributeName=mail
 ldap.synchronization.userOrganizationalIdAttributeName=o
 ldap.synchronization.defaultHomeFolderProvider=largeHomeFolderProvider
 ldap.synchronization.groupIdAttributeName=cn
 ldap.synchronization.groupDisplayNameAttributeName=description
 ldap.synchronization.personType=inetOrgPerson
 ldap.synchronization.groupType==groupOfNames
 ldap.synchronization.groupMemberAttributeName=member
 ldap.synchronization.enableProgressEstimation=true
 ldap.authentication.java.naming.read.timeout=0

The path for this file should be

/opt/alfresco/tomcat/shared/classes/alfresco/extension/subsystems/Authentication/ldap/ldap1/ldap-authentication.properties

Now edit your alfresco global properties to call the new class for authentication and sync, just add the following to the top

### Use Alfresco authentication for admin accounts and LDAP for users ###
authentication.chain=alfrescoNtlm1:alfrescoNtlm,ldap1:ldap
## For DEV, set synchronizeChangesOnly to false for FULL SYNC
synchronization.synchronizeChangesOnly=true
## Set up regular synchronization with the LDAP server ##
synchronization.syncWhenMissingPeopleLogIn=true
synchronization.syncOnStartup=true
synchronization.import.cron=0 */15 * * * ?

And ce’st ca., you will be synchronizing with LDAP every 15 mins or on startup, so maybe a good time to restart the alfresco server and see if it works.

 

 

 

 

OpenLdap with multiple domains


OpenLDAP or SLAPD, the heart of Zimbra authentication and Samba/AD. Not as easy as the click-er-die-click interface of Windows, but when set up correctly, just as powerful.

My headache came however when I wanted to host multiple domains or databases on the same server. One server that is the directory for a.com and b.com and maybe even c.com, you get the drift.

Lesson one is to never to modify the /usr/share/slapd/slapd.conf file, configuration of OpenLdap is done through LDIF files and ldapadd.

Now the first thing we do is actually install OpenLdap and the Tools

apt-get install slapd ldap-utils
 mkdir /ldap
 chown -R openldap:openldap /ldap

Now if you already had OpenLdap/SlapD installed, purge and reinstall it like so

apt-get purge slapd ldap-utils --YES && wait
rm /var/lib/ldap/*
rm -rf /etc/ldap
rm -rf /ldap
apt-get install slapd ldap-utils
mkdir /ldap
chown -R openldap:openldap /ldap

The (re) installation will ask you for a password (from the dpkg-configure) I have not bothered to silence that yet.

You see the script made a folder /ldap and made openldap owner of that, since I don’t like to hide my databases somewhere in /var/lib

Next is to tell the AppArmor watchdog to leave our /LDAP folder alone

nano /etc/apparmor.d/usr.sbin.slapd 

and edit the section databases and logsto look like this

 # the databases and logs
 /var/lib/ldap/ r,
 /var/lib/ldap/** rwk,
 /ldap/ r,
 /ldap/** rwk,

And restart the Apparmor:

service apparmor restart

Now, the meat and potatoes, which I called createdomain.sh all in one shell script file of course, but cut up a bit here to explain whats what.

!/bin/sh
PASS=$(slappasswd -s Supersecretpassword)
DOMAINNAME=SomeDomain;
DOMAINEXT=SomeExtension
DATABASEID==$(ar=$(ls /etc/ldap/slapd.d/cn\=config/*{?}* | cut -d "{" -f2 | cut -d "}" -f1)&&nr=$(($(echo "${ar[*]}" | sort -nr | head -n1) + 1))&&echo $nr)
TEMP=/tmp

The variables, yes I know , clear text passwords, next time i’ll MD5 them. The database ID is the number of the DB. Get the currently used ones from  etc/ldap/slapd.d/cn\=config/*{?}* and a little bash magic adds one to the tally.

Now add the database folder and chown it to openldap, if it already exists the domain must already be created, so better stop there..

if [ ! -d /ldap/$DOMAINNAME-$DOMAINEXT ]; then
 mkdir /ldap/$DOMAINNAME-$DOMAINEXT
 chown -R openldap:openldap /ldap/$DOMAINNAME-$DOMAINEXT
else
 echo "Domain $DOMAINNAME.$DOMAINEXT exists, aborting"
 exit 1
fi
echo Building $DOMAINNAME.$DOMAINEXT in database /ldap/$DOMAINNAME-$DOMAINEXT

Next up is construct the LDIF file with a simple cat << EOF >

cat << EOF > $TEMP/database.ldif
# Create directory database
dn: olcDatabase={$DATABASEID}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {$DATABASEID}hdb
olcDbDirectory: /ldap/$DOMAINNAME-$DOMAINEXT
olcSuffix: dc=$DOMAINNAME,dc=$DOMAINEXT
olcRootDN: cn=admin,dc=$DOMAINNAME,dc=$DOMAINEXT
olcRootPW: $PASS
olcAccess: to attrs=userPassword 
 by dn="cn=admin,dc=$DOMAINNAME,dc=$DOMAINEXT" write 
 by anonymous auth 
 by self write 
 by * none
olcAccess: to attrs=shadowLastChange 
 by self write 
 by * read
olcAccess: to dn.base="" 
 by * read
olcAccess: to * 
 by dn="cn=admin,dc=$DOMAINNAME,dc=$DOMAINEXT" write 
 by * read
olcDbCheckpoint: 512 30
olcDbConfig: {0}set_cachesize 0 2097152 0
olcDbConfig: {1}set_lk_max_objects 1500
olcDbConfig: {2}set_lk_max_locks 1500
olcDbConfig: {3}set_lk_max_lockers 1500
olcDbIndex: uid pres,eq
olcDbIndex: cn,sn,mail pres,eq,approx,sub
olcDbIndex: objectClass eq
# Modifications
dn: cn=config
changetype: modify
dn: olcDatabase={-1}frontend,cn=config
changetype: modify
delete: olcAccess
dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcRootDN
olcRootDN: cn=admin,cn=config
dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcRootPW
olcRootPW: $PASS
dn: olcDatabase={0}config,cn=config
changetype: modify
delete: olcAccess
EOF
Followed by the LDAPADD that imports the database 

ldapadd -Y EXTERNAL -H ldapi:/// -f $TEMP/database.ldif
rm $TEMP/database.ldif

Due to the unique way ldapadd reads config files, sometimes the olcAccess: class causes an ldap error 80. when this happens, make sure each line in the olcAccess class has a trailing space. 

Now it is time to fill the newly created database with a base structure. Same cat <<EOF there followed by another ldapadd

cat << EOF > $TEMP/dit.ldif
# Tree root
dn: dc=$DOMAINNAME,dc=$DOMAINEXT
objectClass: dcObject
objectclass: organization
o: $DOMAINNAME.$DOMAINEXT
dc: $DOMAINNAME
description: Tree root
# Populating
dn: cn=admin,dc=$DOMAINNAME,dc=$DOMAINEXT
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
userPassword: $PASS
description: LDAP administrator
dn: ou=users,dc=$DOMAINNAME,dc=$DOMAINEXT
ou: users
objectClass: organizationalUnit
objectClass: top
dn: ou=groups,dc=$DOMAINNAME,dc=$DOMAINEXT
ou: groups
objectClass: organizationalUnit
objectClass: top
#Adding user
dn: uid=test,ou=users,dc=$DOMAINNAME,dc=$DOMAINEXT
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: test
sn: test
givenName: test
cn: test test
displayName: test test
uidNumber: 1002
gidNumber: 1000
userPassword: $PASS
gecos: test test
loginShell: /bin/bash
homeDirectory: /home/test
shadowExpire: -1
shadowFlag: 0
shadowWarning: 7
shadowMin: 8
shadowMax: 999999
shadowLastChange: 10877
mail: test@$DOMAINNAME.$DOMAINEXT
postalCode: 31000
l: test
o: $DOMAINNAME
mobile: +852 12345678
homePhone: +852 12345678
title: test user
postalAddress:
initials: tst
EOF
ldapadd -x -D cn=admin,dc=$DOMAINNAME,dc=$DOMAINEXT -W -f $TEMP/dit.ldif

Finally, for good measures  I normally add some certificates for the SSL authentication, I am assuming I do not need to explain how to create some SSL certs..

dn: cn=config
changetype: modify
add: olcTLSCipherSuite
olcTLSCipherSuite: NORMAL
-
add: olcTLSCRLCheck
olcTLSCRLCheck: none
-
add: olcTLSVerifyClient
olcTLSVerifyClient: never
-
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ssl/certs/ldap-ca-cert.pem
-
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ssl/private/ldap-ca-key.pem

and apply with ldapadd

ldapadd -Y EXTERNAL -H ldapi:/// -f ssl.ldif

Now when all is quare and equal, you should have added a domain database. I use JXplorer to check if all is well, just connect into the cn=config for the full picture.

Next up is good old replication, but I’ll save that for another time..

Cest Ca.