diff --git a/src/python/dm/common/utility/ldapLinuxPlatformUtility.py b/src/python/dm/common/utility/ldapLinuxPlatformUtility.py
new file mode 100755
index 0000000000000000000000000000000000000000..74f1d17e1a8518b3f774d655dd6cf2a11feeda53
--- /dev/null
+++ b/src/python/dm/common/utility/ldapLinuxPlatformUtility.py
@@ -0,0 +1,187 @@
+#!/usr/bin/env python
+
+import ldap
+import ldap.modlist
+import copy
+
+from dm.common.utility.loggingManager import LoggingManager
+from dm.common.exceptions.configurationError import ConfigurationError
+from dm.common.exceptions.internalError import InternalError
+from dm.common.exceptions.authenticationError import AuthenticationError
+from dm.common.exceptions.communicationError import CommunicationError
+from dmSubprocess import DmSubprocess
+
+class LdapLinuxPlatformUtility:
+
+    SUDO_CMD = '/usr/bin/sudo'
+    GROUPADD_CMD = '/usr/sbin/groupadd'
+    USERMOD_CMD = '/usr/sbin/usermod'
+    SETFACL_CMD = '/usr/bin/setfacl'
+    CHOWN_CMD = '/bin/chown'
+
+    def __init__(self, serverUrl, adminDn, adminPasswordFile, groupDnFormat, minGidNumber=None):
+        self.serverUrl = serverUrl
+        self.adminDn = adminDn
+        self.groupDnFormat = groupDnFormat
+        self.minGidNumber = minGidNumber
+        self.getLogger().debug('Min GID number: %s' % minGidNumber)
+        # Remove first entry from the dn format to get tree base
+        self.groupBaseDn = ','.join(groupDnFormat.split(',')[1:])
+        self.getLogger().debug('Group base DN: %s' % self.groupBaseDn)
+        self.getLogger().debug('Using LDAP Admin password file: %s' % adminPasswordFile)
+        self.adminPassword = open(adminPasswordFile, 'r').readline().strip()
+        if not self.adminPassword:
+            raise ConfigurationError('LDAP password could not be found in %s file' % adminPasswordFile) 
+        self.ldapClient = None
+
+    @classmethod
+    def getLogger(cls):
+        logger = LoggingManager.getInstance().getLogger(cls.__name__)
+        return logger
+
+    @classmethod
+    def executeSudoCommand(cls, cmd):
+        p = DmSubprocess('%s %s' % (cls.SUDO_CMD, cmd))
+        p.run()
+
+    def getLdapClient(self):
+        if self.ldapClient is not None:
+            try:
+                self.ldapClient.simple_bind_s(self.adminDn, self.adminPassword)
+            except Exception, ex:
+                self.getLogger().error('Invalidating LDAP client due to error: %s' % ex)
+                self.unbind(self.ldapClient)
+                self.ldapClient = None
+
+        if not self.ldapClient:
+            self.ldapClient = self.bind(self.serverUrl, self.adminDn, self.adminPassword)
+        return self.ldapClient
+
+    @classmethod 
+    def bind(cls, serverUrl, adminDn, adminPassword):
+        try:
+            ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
+            ldapClient = ldap.initialize(serverUrl)
+            ldapClient.set_option(ldap.OPT_REFERRALS,0)
+            ldapClient.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3)
+            ldapClient.simple_bind_s(adminDn, adminPassword)
+            cls.getLogger().debug('Successful binding with LDAP DN: %s' % adminDn)
+            return ldapClient
+        except ldap.INVALID_CREDENTIALS, ex:
+            ldapClient.unbind()
+            raise AuthenticationError('Invalid LDAP credentials for admin user %s' % adminDn)
+        except ldap.SERVER_DOWN, ex:
+            raise CommunicationError('Cannot reach LDAP server %s' % serverUrl)
+        except Exception, ex:
+            raise InternalError('Unrecognized exception while binding to LDAP server %s: %s' % (serverUrl, ex))
+
+    @classmethod 
+    def unbind(cls, ldapClient):
+        try:
+            ldapClient.unbind()
+        except Exception, ex:
+            cls.getLogger().error('Could not unbind LDAP client: %s' % ex)
+
+    def createGroup(self, name):
+        """ Create group if it does not exist. """
+        logger = self.getLogger()
+        ldapClient = self.getLdapClient()
+        try:
+            groupDn = self.groupDnFormat % name
+            logger.debug('Looking for group DN: %s' % groupDn)
+            # this method will throw exception if group is not found
+            resultList = ldapClient.search_s(groupDn, ldap.SCOPE_BASE)
+            groupTuple = resultList[0]
+            logger.debug('Group %s already exists' % groupTuple[0])
+            return
+        except ldap.NO_SUCH_OBJECT, ex:
+            logger.debug('Group DN %s must be created' % groupDn)
+        except Exception, ex:
+            raise InternalError(exception=ex)
+
+        # determine gidNumber: look through all entries to get max value,
+        # then increment it
+        # ldap should really be configured to handle gid's automatically,
+        # and should prevent invalid entries
+        try:
+            logger.debug('Looking for max group id')
+            resultList = ldapClient.search_s(self.groupBaseDn, ldap.SCOPE_ONELEVEL, attrlist=['gidNumber'])
+            maxGid = 0
+            if self.minGidNumber:
+                maxGid = self.minGidNumber 
+            for result in resultList:
+                gidList = result[1].get('gidNumber', [])
+                gid = 0
+                if gidList:
+                    gid = int(gidList[0])
+
+                if gid > maxGid:
+                    maxGid = gid
+            gidNumber = str(maxGid + 1)
+            logger.debug('Max GID is %s, new group id will be %s' % (maxGid, gidNumber)) 
+        except Exception, ex:
+            raise InternalError(exception=ex)
+        
+        attrs = {}
+        attrs['objectclass'] = ['posixGroup','top']
+        attrs['cn'] = name
+        attrs['gidNumber'] = [gidNumber]
+        attrs['memberUid'] = []
+        try:
+            groupLdif = ldap.modlist.addModlist(attrs)
+            ldapClient.add_s(groupDn, groupLdif)
+        except Exception, ex:
+            logger.error('Could not add group %s: %s' % (groupDn, ex))
+            raise InternalError(exception=ex)
+
+    def addUserToGroup(self, username, groupName):
+        """ Add user to group. """
+        logger = self.getLogger()
+        ldapClient = self.getLdapClient()
+        try:
+            groupDn = self.groupDnFormat % groupName
+            resultList = ldapClient.search_s(groupDn, ldap.SCOPE_BASE)
+            groupTuple = resultList[0]
+            groupAttrs = groupTuple[1]
+            memberUidList = groupAttrs.get('memberUid', [])
+            if username in memberUidList:
+                logger.debug('Group %s already contains user %s' % (groupName, username))
+                return
+        except Exception, ex:
+            raise InternalError(exception=ex)
+        logger.debug('Adding user %s to group %s' % (username, groupName))
+        memberUidList2 = copy.copy(memberUidList)
+        memberUidList2.append(username)
+        groupAttrs2 = copy.copy(groupAttrs)
+        groupAttrs2['memberUid'] = memberUidList2
+        try:
+            groupLdif = ldap.modlist.modifyModlist(groupAttrs, groupAttrs2)
+            ldapClient.modify_s(groupDn, groupLdif)
+        except Exception, ex:
+            logger.error('Could not add user %s to group %s: %s' % (username, groupName, ex))
+            raise InternalError(exception=ex)
+
+    @classmethod
+    def setPathReadExecutePermissionsForGroup(cls, path, groupName):
+        """ Set path permissions for the given group. """
+        logger = cls.getLogger()
+        logger.debug('Allowing group %s to read/execute path %s' % (groupName, path))
+        cmd = '%s -m group\:%s\:rx %s' % (cls.SETFACL_CMD, groupName, path)
+        cls.executeSudoCommand(cmd)
+
+    @classmethod
+    def changePathGroupOwner(cls, path, groupName):
+        logger = cls.getLogger()
+        logger.debug('Changing group owner to %s for path %s' % (groupName, path))
+        cmd = '%s -R \:%s %s' % (cls.CHOWN_CMD, groupName, path)
+        cls.executeSudoCommand(cmd)
+
+#######################################################################
+# Testing.
+
+if __name__ == '__main__':
+    utility = LdapLinuxPlatformUtility('ldaps://dmid-vm.xray.aps.anl.gov:636', 'uid=dmadmin,ou=People,o=aps.anl.gov,dc=aps,dc=anl,dc=gov', '/tmp/ldapPassword', groupDnFormat='cn=%s,ou=DM,ou=Group,o=aps.anl.gov,dc=aps,dc=anl,dc=gov', minGidNumber=66000)
+    utility.createGroup('exp2')
+    #utility.createGroup('dmgp000001_TOF')
+    utility.addUserToGroup('rs1', 'exp2')
+