Active Directory to OpenLDAP Sync with LSC

I have recently had to sync accounts and groups from Activc Directory to OpenLDAP, for a requirement for a directory server in the DMZ.  A DMZ (De-millitarised zone) is an area of the network open to the internet.  It’s supposed to be separate from the rest of your LAN, so you can have services running on the internet without fear that people can break into your LAN from these.

There are other options for doing this, including a read-only domain controller (RODC), a AD LDS (Lighweight Directory Server) and so on, but they all require connectivity back from the DMZ to the LAN, which is precisely what we are trying to avoid.

If you start from the premise that no traffic at all be allowed to flow into the LAN from the DMZ, then how do you authenticate your user’s accounts?  The only real answer is a directory server in the DMZ, and to save our own users having to have multiple logins, clearly some sort of account sync would be required.

We looked at a tool called LSC (LDAP Syncronisation Connector) which is designed for syncing various directory sources to and from each other.  It’s a very capable product, and now I’ve gone through the learning process, I will have to remember if for similar functions in the future (it can’t read/write from databases, CSV files and so on too).

In order to get it set up, there are some gotchas, not least password sync, which requires another method.  But I will leave discussion of that until later.  First of all, I needed to get our users and groups into OpenLDAP from Active Directory.

To set this up required a config file, a modified version of which is below:

<?xml version=”1.0″ ?>

<lsc xmlns=”http://lsc-project.org/XSD/lsc-core-2.0.xsd&#8221; revision=”0″>

<connections>

<ldapConnection>

<name>dst-ldap</name>

<url>ldaps://myopenldapserver:636/DC=mydomain,DC=co,DC=uk</url>

<username>cn=Manager,DC=mydomain,DC=co,DC=uk</username>

<password>mypassword</password>

<authentication>SIMPLE</authentication>

<referral>IGNORE</referral>

<derefAliases>NEVER</derefAliases>

<version>VERSION_3</version>

<pageSize>-1</pageSize>

<factory>com.sun.jndi.ldap.LdapCtxFactory</factory>

<tlsActivated>false</tlsActivated>

<saslMutualAuthentication>false</saslMutualAuthentication>

</ldapConnection>

<ldapConnection>

<name>src-ad</name>

<url>ldap://myADserver:389/OU=mydomain,DC=mydomain,DC=local</url>

<username>chrisgilbert@mydomain.local</username>

<password>mypassword</password>

<authentication>SIMPLE</authentication>

<pageSize>1000</pageSize>

</ldapConnection>

</connections>

<audits/>

<tasks>

<task>

<name>MySyncTask</name>

<bean>org.lsc.beans.SimpleBean</bean>

<ldapSourceService>

<name>MySyncTask-src</name>

<connection reference=”src-ad” />

<baseDn>OU=mydomain,DC=mydomain,DC=local</baseDn>

<pivotAttributes>

<string>userPrincipalName</string>

</pivotAttributes>

<fetchedAttributes>

<string>cn</string>

<string>sn</string>

<string>givenName</string>

<string>mail</string>

<string>sAMAccountName</string>

<string>userPrincipalName</string>

</fetchedAttributes>

<getAllFilter>(&amp;(mail=*)(objectClass=user))</getAllFilter>

<getOneFilter>(&amp;(userPrincipalName={userPrincipalName})(objectClass=user))</getOneFilter>

<cleanFilter>(&amp;(userPrincipalName={userPrincipalName})(objectClass=user))</cleanFilter>

<interval>6</interval>

</ldapSourceService>

<ldapDestinationService>

<name>MySyncTask-dst</name>

<connection reference=”dst-ldap”/>

<baseDn>ou=mydomain,DC=mydomain,DC=co,DC=uk</baseDn>

<pivotAttributes>

<string>mail</string>

</pivotAttributes>

<fetchedAttributes>

<string>cn</string>

<string>sn</string>

<string>objectClass</string>

<string>givenName</string>

<string>mail</string>

<string>uid</string>

</fetchedAttributes>

<getAllFilter>(objectClass=inetOrgPerson)</getAllFilter>

<getOneFilter>(&amp;(objectClass=inetOrgPerson)(mail={mail}))</getOneFilter>

</ldapDestinationService>

<propertiesBasedSyncOptions>

<mainIdentifier>”mail=” + srcBean.getDatasetFirstValueById(“mail”)

+ “,ou=mydomain,DC=mydomain,DC=co,DC=uk”</mainIdentifier>

<defaultDelimiter>;</defaultDelimiter>

<defaultPolicy>FORCE</defaultPolicy>

<dataset>

<name>objectClass</name>

<policy>FORCE</policy>

<forceValues>

<string>”inetOrgPerson”</string>

<string>”organizationalPerson”</string>

<string>”person”</string>

<string>”top”</string>

</forceValues>

<delimiter>,</delimiter>

</dataset>

<dataset>

<name>uid</name>

<policy>FORCE</policy>

<forceValues>

<string>

srcBean.getDatasetFirstValueById(“sAMAccountName”)</string>

</forceValues>

</dataset>

<dataset>

<name>default</name>

<policy>FORCE</policy>

</dataset>

</propertiesBasedSyncOptions>

</task>

<task>

<name>GroupSyncTask</name>

<bean>org.lsc.beans.SimpleBean</bean>

<ldapSourceService>

<name>GroupSyncTask-src</name>

<connection reference=”src-ad” />

<baseDn>OU=mydomain,DC=mydomain,DC=local</baseDn>

<pivotAttributes>

<string>cn</string>

</pivotAttributes>

<fetchedAttributes>

<string>cn</string>

<string>member</string>

</fetchedAttributes>

<getAllFilter>(&amp;(objectClass=group)(member=*)(|(cn=-sec-Jira*)(cn=-sec-Confluence*)))</getAllFilter>

<getOneFilter>(&amp;(objectClass=group)(cn={cn}))</getOneFilter>

<cleanFilter>(&amp;(objectClass=group)(cn={cn}))</cleanFilter>

<interval>100</interval>

</ldapSourceService>

<ldapDestinationService>

<name>GroupSyncTask-dst</name>

<connection reference=”dst-ldap”/>

<baseDn>ou=groups,DC=mydomain,DC=co,DC=uk</baseDn>

<pivotAttributes>

<string>cn</string>

</pivotAttributes>

<fetchedAttributes>

<string>cn</string>

<string>member</string>

<string>objectClass</string>

</fetchedAttributes>

<getAllFilter>(objectClass=groupOfNames)</getAllFilter>

<getOneFilter>(&amp;(objectClass=groupOfNames)(cn={cn}))</getOneFilter>

</ldapDestinationService>

<propertiesBasedSyncOptions>

<mainIdentifier>”cn=” + srcBean.getDatasetValuesById(“cn”)+

“,ou=groups,DC=mydomain,DC=co,DC=uk”</mainIdentifier>

<defaultDelimiter>;</defaultDelimiter>

<defaultPolicy>FORCE</defaultPolicy>

<dataset>

<name>objectClass</name>

<policy>FORCE</policy>

<forceValues>

<string>”groupOfNames”</string>

<string>”top”</string>

</forceValues>

<delimiter>$</delimiter>

</dataset>

<dataset>

<name>default</name>

<policy>FORCE</policy>

</dataset>

</propertiesBasedSyncOptions>

</task>

</tasks>

</lsc>

I had a few specific requirements – I wanted to sync only some of the groups, as we have hundreds, so I filtered out the security groups related to Confluence and Jira (our customer facing systems).  I also wanted to change the distinguished names (DNs) of the objects as I moved them, from mydomain.local to mydomain.co.uk.  In LDAP speak that is from dc=mydomain,dc=local to dc=mydomain,dc=co,dc=uk.

I won’t go into explaining the config too much, you need to know a bit about LDAP to understand it.  I am “lucky” enough to have delved into LDAP search criteria before, so it wasn’t too challenging.  However, for everyone else, a good bit of googling and trial and error will hopefully produce something useful.

This works for me – use it and modify it if you like.  I wasn’t able to find a good example for the 2.0.x series of LSC (with the new XML config files) so hopefully this will help some people.  I put it together from some other posts I found on the mailing lists, along with suggestions on how they should be fixed, to come up with something that worked.

The second phase of this is making password sync also work.  LSC cannot do this by itself, but does come with a perl script which can be hooked in via a third party program called hkpassword, and send the password changes to OpenLDAP as they occur.  I got this working fine, with a few modifications.  I’ll post this at a later date when I’ve had a chance to write up and document the process.

10 thoughts on “Active Directory to OpenLDAP Sync with LSC

  1. Hi Chris,
    how I can synchronizing passwords (no plain text) between the openldap and Active Directory ?

  2. Hi Chris,

    Thanks for this. I was curious, did this config allow you to receive event notifications from Active Directory ? Namely, when an entry changed there, did lsc receive that change event automatically and near instantly ? That is what I am looking to do with no luck so far but I’m looking a bit closer at your configuration.

    1. Hi, if I remember correctly, this just synced on a schedule. It didn’t have a way of receiving events at the time. I am not sure if LSC can do that or not – it worked well for me as a scheduled tool, and is very flexible, but not that easy to get working for all purposes.

      It’s worth looking into AD LDS and federation as alternative approaches. If an external organisation needs access to AD records, then something like using federation on Azure is worth a look too (https://azure.microsoft.com/en-us/documentation/articles/active-directory-aadconnect-azure-adfs/). But in our case we just cared about having a strongly enforced DMZ.

      1. Oh, I almost forgot, at Hudl we use Okta as a powerful alternative for authenticating to cloud services. Worth a look.

  3. Thanks for the article.

    I didn’t find anything in the web about hkpassword.
    Is the tool still available?

    Are you aware of other ways to sync the passwords from the AD?

    1. I’ve had a quick look around and I can’t find it now either. My article is a few years old now, and I work somewhere different, so can’t be sure I’m giving you great advice. However – first check this method is the best one to meet your use case.

      Since I wrote it, ADFS (federation services) are much better, and Microsoft also host a Azure based AD which can sync with your on-prem one. We were trying to create a strict DMZ, which we believed at the time was required, but there were other ways of solving the problem too.

      Also look at using newer real authentication protocols like OAuth, SAML and so on to solve single-sign on problems. LDAP is really an old fall back these days, and is not a particularly secure way of authenticating.

      Also, check out Okta SSO – this is a good way to control access to cloud products that your team use, hooked into AD auth. It works well and has Chrome/Firefox plugins and mobile apps, that’s something we use at hudl.

      If you give me a bit more information on the problems you are trying to solve I can maybe help further. For most companies, I’d start looking at a cloud first solution to SSO and authentication sharing because most people are accessing cloud apps all over the place now, with or without the IT department’s consent.

Leave a Reply to chrisgilbert42 Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s