You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by GitBox <gi...@apache.org> on 2018/01/06 17:28:36 UTC

[GitHub] rhtyd closed pull request #2381: CLOUDSTACK-10117 Account ldap binding

rhtyd closed pull request #2381: CLOUDSTACK-10117 Account ldap binding
URL: https://github.com/apache/cloudstack/pull/2381
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java b/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java
index 8f71f48470e..80ebaf43f64 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java
@@ -19,6 +19,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.cloudstack.api.response.DomainResponse;
 import org.apache.log4j.Logger;
 
 import org.apache.cloudstack.api.APICommand;
@@ -77,6 +78,12 @@
                description = "the ID of the Account to update the parameter value for corresponding account")
     private Long accountId;
 
+    @Parameter(name = ApiConstants.DOMAIN_ID,
+               type = CommandType.UUID,
+               entityType = DomainResponse.class,
+               description = "the ID of the Domain to update the parameter value for corresponding domain")
+    private Long domainId;
+
     @Parameter(name = ApiConstants.IMAGE_STORE_UUID,
             type = CommandType.UUID,
             entityType = ImageStoreResponse.class,
@@ -111,6 +118,10 @@ public Long getAccountId() {
         return accountId;
     }
 
+    public Long getDomainId() {
+        return domainId;
+    }
+
     public Long getImageStoreId() {
         return imageStoreId;
     }
@@ -158,6 +169,9 @@ public void execute() {
             if (getAccountId() != null) {
                 cfgResponse.setScope("account");
             }
+            if (getDomainId() != null) {
+                cfgResponse.setScope("domain");
+            }
             if (getImageStoreId() != null){
                 cfgResponse.setScope("imagestore");
             }
diff --git a/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java b/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
index fa5e26e418f..936f0cd69f1 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
@@ -18,6 +18,7 @@
 
 import com.google.common.base.Strings;
 import org.apache.cloudstack.acl.RoleService;
+import org.apache.cloudstack.api.response.DomainResponse;
 import org.apache.log4j.Logger;
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiArgValidator;
@@ -76,6 +77,12 @@
                description = "the ID of the Account to update the parameter value for corresponding account")
     private Long accountId;
 
+    @Parameter(name = ApiConstants.DOMAIN_ID,
+               type = CommandType.UUID,
+               entityType = DomainResponse.class,
+               description = "the ID of the Domain to update the parameter value for corresponding domain")
+    private Long domainId;
+
     @Parameter(name = ApiConstants.IMAGE_STORE_UUID,
             type = CommandType.UUID,
             entityType = ImageStoreResponse.class,
@@ -115,6 +122,10 @@ public Long getAccountId() {
         return accountId;
     }
 
+    public Long getDomainId() {
+        return domainId;
+    }
+
     public Long getImageStoreId() {
         return imageStoreId;
     }
@@ -157,6 +168,9 @@ public void execute() {
             if (getAccountId() != null) {
                 response.setScope("account");
             }
+            if (getDomainId() != null) {
+                response.setScope("domain");
+            }
             response.setValue(value);
             this.setResponseObject(response);
         } else {
diff --git a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml
index 8a0d7cdde5c..84c27583925 100644
--- a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml
+++ b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml
@@ -147,6 +147,7 @@
   <bean id="engineDcDetailsDaoImpl" class="org.apache.cloudstack.engine.datacenter.entity.api.db.dao.DcDetailsDaoImpl" />
   <bean id="diskOfferingJoinDaoImpl" class="com.cloud.api.query.dao.DiskOfferingJoinDaoImpl" />
   <bean id="domainDaoImpl" class="com.cloud.domain.dao.DomainDaoImpl" />
+  <bean id="domainDetailsDaoImpl" class="com.cloud.domain.dao.DomainDetailsDaoImpl" />
   <bean id="domainJoinDaoImpl" class="com.cloud.api.query.dao.DomainJoinDaoImpl" />
   <bean id="domainRouterDaoImpl" class="com.cloud.vm.dao.DomainRouterDaoImpl" />
   <bean id="domainRouterJoinDaoImpl" class="com.cloud.api.query.dao.DomainRouterJoinDaoImpl" />
diff --git a/engine/schema/resources/META-INF/db/schema-41000to41100.sql b/engine/schema/resources/META-INF/db/schema-41000to41100.sql
index 585c7fd4992..283844e96d6 100644
--- a/engine/schema/resources/META-INF/db/schema-41000to41100.sql
+++ b/engine/schema/resources/META-INF/db/schema-41000to41100.sql
@@ -451,7 +451,7 @@ CREATE VIEW `cloud`.`volume_view` AS
         `cloud`.`domain` resource_tag_domain ON resource_tag_domain.id = resource_tags.domain_id;
 
 -- Extra Dhcp Options
-CREATE TABLE `cloud`.`nic_extra_dhcp_options` (
+CREATE TABLE  IF NOT EXISTS `cloud`.`nic_extra_dhcp_options` (
   `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
   `uuid` varchar(255) UNIQUE,
   `nic_id` bigint unsigned NOT NULL COMMENT ' nic id where dhcp options are applied',
@@ -523,3 +523,20 @@ ADD COLUMN `forsystemvms` TINYINT(1) NOT NULL DEFAULT '0' COMMENT 'Indicates if
 
 ALTER TABLE `cloud`.`op_dc_ip_address_alloc`
 ADD COLUMN `vlan` INT(10) UNSIGNED NULL COMMENT 'Vlan the management network range is on';
+
+-- ldap binding on domain level
+CREATE TABLE IF NOT EXISTS `cloud`.`domain_details` (
+    `id` bigint unsigned NOT NULL auto_increment,
+    `domain_id` bigint unsigned NOT NULL COMMENT 'account id',
+    `name` varchar(255) NOT NULL,
+    `value` varchar(255) NOT NULL,
+    PRIMARY KEY (`id`),
+    CONSTRAINT `fk_domain_details__domain_id` FOREIGN KEY (`domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE
+)ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+ALTER TABLE cloud.ldap_configuration ADD COLUMN domain_id BIGINT(20) DEFAULT NULL;
+ALTER TABLE cloud.ldap_trust_map ADD COLUMN account_id BIGINT(20) DEFAULT 0;
+ALTER TABLE cloud.ldap_trust_map DROP FOREIGN KEY fk_ldap_trust_map__domain_id;
+DROP INDEX uk_ldap_trust_map__domain_id ON cloud.ldap_trust_map;
+CREATE UNIQUE INDEX uk_ldap_trust_map__bind_location ON ldap_trust_map (domain_id, account_id);
+
diff --git a/engine/schema/src/com/cloud/domain/DomainDetailVO.java b/engine/schema/src/com/cloud/domain/DomainDetailVO.java
new file mode 100644
index 00000000000..61eb6cfd28e
--- /dev/null
+++ b/engine/schema/src/com/cloud/domain/DomainDetailVO.java
@@ -0,0 +1,76 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+package com.cloud.domain;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import com.cloud.utils.db.Encrypt;
+import org.apache.cloudstack.api.InternalIdentity;
+
+@Entity
+@Table(name = "domain_details")
+public class DomainDetailVO implements InternalIdentity {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id")
+    private long id;
+
+    @Column(name = "domain_id")
+    private long domainId;
+
+    @Column(name = "name")
+    private String name;
+
+    @Encrypt
+    @Column(name = "value")
+    private String value;
+
+    protected DomainDetailVO() {
+    }
+
+    public DomainDetailVO(long domainId, String name, String value) {
+        this.domainId = domainId;
+        this.name = name;
+        this.value = value;
+    }
+
+    public long getDomainId() {
+        return domainId;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    @Override
+    public long getId() {
+        return id;
+    }
+}
diff --git a/engine/schema/src/com/cloud/domain/dao/DomainDetailsDao.java b/engine/schema/src/com/cloud/domain/dao/DomainDetailsDao.java
new file mode 100644
index 00000000000..51362cf885e
--- /dev/null
+++ b/engine/schema/src/com/cloud/domain/dao/DomainDetailsDao.java
@@ -0,0 +1,34 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+package com.cloud.domain.dao;
+
+import java.util.Map;
+
+import com.cloud.domain.DomainDetailVO;
+import com.cloud.utils.db.GenericDao;
+
+public interface DomainDetailsDao extends GenericDao<DomainDetailVO, Long> {
+    Map<String, String> findDetails(long domainId);
+
+    void persist(long domainId, Map<String, String> details);
+
+    DomainDetailVO findDetail(long domainId, String name);
+
+    void deleteDetails(long domainId);
+
+    void update(long domainId, Map<String, String> details);
+}
diff --git a/engine/schema/src/com/cloud/domain/dao/DomainDetailsDaoImpl.java b/engine/schema/src/com/cloud/domain/dao/DomainDetailsDaoImpl.java
new file mode 100644
index 00000000000..ad7f7040207
--- /dev/null
+++ b/engine/schema/src/com/cloud/domain/dao/DomainDetailsDaoImpl.java
@@ -0,0 +1,104 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+package com.cloud.domain.dao;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.cloud.domain.DomainDetailVO;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.QueryBuilder;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.SearchCriteria.Op;
+import com.cloud.utils.db.TransactionLegacy;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.framework.config.ConfigKey.Scope;
+import org.apache.cloudstack.framework.config.ScopedConfigStorage;
+
+public class DomainDetailsDaoImpl extends GenericDaoBase<DomainDetailVO, Long> implements DomainDetailsDao, ScopedConfigStorage {
+    protected final SearchBuilder<DomainDetailVO> domainSearch;
+
+    protected DomainDetailsDaoImpl() {
+        domainSearch = createSearchBuilder();
+        domainSearch.and("domainId", domainSearch.entity().getDomainId(), Op.EQ);
+        domainSearch.done();
+    }
+
+    @Override
+    public Map<String, String> findDetails(long domainId) {
+        QueryBuilder<DomainDetailVO> sc = QueryBuilder.create(DomainDetailVO.class);
+        sc.and(sc.entity().getDomainId(), Op.EQ, domainId);
+        List<DomainDetailVO> results = sc.list();
+        Map<String, String> details = new HashMap<String, String>(results.size());
+        for (DomainDetailVO r : results) {
+            details.put(r.getName(), r.getValue());
+        }
+        return details;
+    }
+
+    @Override
+    public void persist(long domainId, Map<String, String> details) {
+        TransactionLegacy txn = TransactionLegacy.currentTxn();
+        txn.start();
+        SearchCriteria<DomainDetailVO> sc = domainSearch.create();
+        sc.setParameters("domainId", domainId);
+        expunge(sc);
+        for (Map.Entry<String, String> detail : details.entrySet()) {
+            DomainDetailVO vo = new DomainDetailVO(domainId, detail.getKey(), detail.getValue());
+            persist(vo);
+        }
+        txn.commit();
+    }
+
+    @Override
+    public DomainDetailVO findDetail(long domainId, String name) {
+        QueryBuilder<DomainDetailVO> sc = QueryBuilder.create(DomainDetailVO.class);
+        sc.and(sc.entity().getDomainId(), Op.EQ, domainId);
+        sc.and(sc.entity().getName(), Op.EQ, name);
+        return sc.find();
+    }
+
+    @Override
+    public void deleteDetails(long domainId) {
+        SearchCriteria<DomainDetailVO> sc = domainSearch.create();
+        sc.setParameters("domainId", domainId);
+        List<DomainDetailVO> results = search(sc, null);
+        for (DomainDetailVO result : results) {
+            remove(result.getId());
+        }
+    }
+
+    @Override
+    public void update(long domainId, Map<String, String> details) {
+        Map<String, String> oldDetails = findDetails(domainId);
+        oldDetails.putAll(details);
+        persist(domainId, oldDetails);
+    }
+
+    @Override
+    public Scope getScope() {
+        return Scope.Domain;
+    }
+
+    @Override
+    public String getConfigValue(long id, ConfigKey<?> key) {
+        DomainDetailVO vo = findDetail(id, key.key());
+        return vo == null ? null : vo.getValue();
+    }
+}
diff --git a/framework/config/src/org/apache/cloudstack/framework/config/ConfigKey.java b/framework/config/src/org/apache/cloudstack/framework/config/ConfigKey.java
index fb2a57b71f6..1734b98757b 100644
--- a/framework/config/src/org/apache/cloudstack/framework/config/ConfigKey.java
+++ b/framework/config/src/org/apache/cloudstack/framework/config/ConfigKey.java
@@ -31,7 +31,7 @@
 public class ConfigKey<T> {
 
     public static enum Scope {
-        Global, Zone, Cluster, StoragePool, Account, ManagementServer, ImageStore
+        Global, Zone, Cluster, StoragePool, Account, ManagementServer, ImageStore, Domain
     }
 
     private final String _category;
diff --git a/framework/config/src/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java b/framework/config/src/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java
index e68fd3cdae3..6a85b90b70d 100644
--- a/framework/config/src/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java
+++ b/framework/config/src/org/apache/cloudstack/framework/config/impl/ConfigDepotImpl.java
@@ -85,6 +85,7 @@ public ConfigDepotImpl() {
         _scopeLevelConfigsMap.put(ConfigKey.Scope.StoragePool, new HashSet<ConfigKey<?>>());
         _scopeLevelConfigsMap.put(ConfigKey.Scope.Account, new HashSet<ConfigKey<?>>());
         _scopeLevelConfigsMap.put(ConfigKey.Scope.ImageStore, new HashSet<ConfigKey<?>>());
+        _scopeLevelConfigsMap.put(ConfigKey.Scope.Domain, new HashSet<ConfigKey<?>>());
     }
 
     @Override
diff --git a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/IntegrationTestConfiguration.java b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/IntegrationTestConfiguration.java
index 7f1d5b805a8..4105a617e6c 100644
--- a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/IntegrationTestConfiguration.java
+++ b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/IntegrationTestConfiguration.java
@@ -140,6 +140,7 @@
 import com.cloud.deploy.DeploymentPlanningManager;
 import com.cloud.deploy.dao.PlannerHostReservationDaoImpl;
 import com.cloud.domain.dao.DomainDaoImpl;
+import com.cloud.domain.dao.DomainDetailsDaoImpl;
 import com.cloud.event.dao.EventDaoImpl;
 import com.cloud.event.dao.EventJoinDaoImpl;
 import com.cloud.event.dao.UsageEventDaoImpl;
@@ -148,8 +149,8 @@
 import com.cloud.host.dao.HostDetailsDaoImpl;
 import com.cloud.host.dao.HostTagsDaoImpl;
 import com.cloud.hypervisor.HypervisorGuruManagerImpl;
-import com.cloud.hypervisor.dao.HypervisorCapabilitiesDaoImpl;
 import com.cloud.hypervisor.XenServerGuru;
+import com.cloud.hypervisor.dao.HypervisorCapabilitiesDaoImpl;
 import com.cloud.network.ExternalDeviceUsageManager;
 import com.cloud.network.IpAddress;
 import com.cloud.network.IpAddressManagerImpl;
@@ -169,8 +170,8 @@
 import com.cloud.network.dao.AccountGuestVlanMapDaoImpl;
 import com.cloud.network.dao.FirewallRulesCidrsDaoImpl;
 import com.cloud.network.dao.FirewallRulesDaoImpl;
-import com.cloud.network.dao.IPAddressDaoImpl;
 import com.cloud.network.dao.IPAddressDao;
+import com.cloud.network.dao.IPAddressDaoImpl;
 import com.cloud.network.dao.LBHealthCheckPolicyDaoImpl;
 import com.cloud.network.dao.LBStickinessPolicyDaoImpl;
 import com.cloud.network.dao.LoadBalancerDaoImpl;
@@ -308,7 +309,7 @@
     ConditionDaoImpl.class, ConfigurationDaoImpl.class, ConfigurationManagerImpl.class, ConfigurationServerImpl.class, ConsoleProxyDaoImpl.class,
     ContrailElementImpl.class, ContrailGuru.class, ContrailManagerImpl.class, CounterDaoImpl.class, DataCenterDaoImpl.class, DataCenterDetailsDaoImpl.class, DataCenterIpAddressDaoImpl.class,
     DataCenterJoinDaoImpl.class, DataCenterLinkLocalIpAddressDaoImpl.class, DataCenterVnetDaoImpl.class, DcDetailsDaoImpl.class, DedicatedResourceDaoImpl.class,
-    DiskOfferingDaoImpl.class, DiskOfferingJoinDaoImpl.class, DomainDaoImpl.class, DomainManagerImpl.class, DomainRouterDaoImpl.class, DomainRouterJoinDaoImpl.class,
+    DiskOfferingDaoImpl.class, DiskOfferingJoinDaoImpl.class, DomainDaoImpl.class, DomainDetailsDaoImpl.class, DomainManagerImpl.class, DomainRouterDaoImpl.class, DomainRouterJoinDaoImpl.class,
     EventDaoImpl.class, EventJoinDaoImpl.class, EventUtils.class, ExtensionRegistry.class, FirewallManagerImpl.class, FirewallRulesCidrsDaoImpl.class,
     FirewallRulesDaoImpl.class, GuestOSCategoryDaoImpl.class, GuestOSDaoImpl.class, HostDaoImpl.class, HostDetailsDaoImpl.class, HostJoinDaoImpl.class,
     HostPodDaoImpl.class, HostTagsDaoImpl.class, HostTransferMapDaoImpl.class, HypervisorCapabilitiesDaoImpl.class, HypervisorGuruManagerImpl.class,
diff --git a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java
index fa933244a66..37ca2bccff4 100644
--- a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java
+++ b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java
@@ -317,7 +317,13 @@ public boolean deleteUser(DeleteUserCmd arg0) {
         return false;
     }
 
-    @Override public boolean moveUser(MoveUserCmd moveUserCmd) {
+    @Override
+    public boolean moveUser(MoveUserCmd moveUserCmd) {
+        return false;
+    }
+
+    @Override
+    public boolean moveUser(long id, Long domainId, long accountId) {
         return false;
     }
 
diff --git a/plugins/user-authenticators/ldap/pom.xml b/plugins/user-authenticators/ldap/pom.xml
index 9f97f08f3fd..e2b0ead17e0 100644
--- a/plugins/user-authenticators/ldap/pom.xml
+++ b/plugins/user-authenticators/ldap/pom.xml
@@ -37,9 +37,9 @@
             <configuration>
               <sources>
                 <fileset>
-                  <directory>test/groovy</directory>
+                  <directory>test</directory>
                   <includes>
-                    <include>**/*.groovy</include>
+                    <include>groovy/**/*.groovy</include>
                   </includes>
                 </fileset>
               </sources>
@@ -70,7 +70,8 @@
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
           <includes>
-            <include>**/*Spec*</include>
+            <include>**/*Spec.groovy</include>
+            <include>**/*Test.java</include>
           </includes>
         </configuration>
       </plugin>
@@ -90,6 +91,7 @@
       </plugin>
 
     </plugins>
+    <testSourceDirectory>test</testSourceDirectory>
   </build>
   <dependencies>
     <!-- Mandatory dependencies for using Spock -->
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LDAPConfigCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LDAPConfigCmd.java
index a138e7ddd4a..cfef21e2aff 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LDAPConfigCmd.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LDAPConfigCmd.java
@@ -49,7 +49,7 @@
  * @deprecated as of 4.3 use the new api {@link LdapAddConfigurationCmd}
  */
 @Deprecated
-@APICommand(name = "ldapConfig", description = "Configure the LDAP context for this site.", responseObject = LDAPConfigResponse.class, since = "3.0.0",
+@APICommand(name = "ldapConfig", description = "(Deprecated, use addLdapConfiguration) Configure the LDAP context for this site.", responseObject = LDAPConfigResponse.class, since = "3.0.0",
         requestHasSensitiveInfo = true, responseHasSensitiveInfo = false)
 
 public class LDAPConfigCmd extends BaseCmd {
@@ -190,8 +190,8 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE
 
             if (result.second() > 0) {
                 boolean useSSlConfig = _ldapConfiguration.getSSLStatus();
-                String searchBaseConfig = _ldapConfiguration.getBaseDn();
-                String bindDnConfig = _ldapConfiguration.getBindPrincipal();
+                String searchBaseConfig = _ldapConfiguration.getBaseDn(null);
+                String bindDnConfig = _ldapConfiguration.getBindPrincipal(null);
                 for (LdapConfigurationVO ldapConfigurationVO : result.first()) {
                     responses.add(createLDAPConfigResponse(ldapConfigurationVO.getHostname(), ldapConfigurationVO.getPort(), useSSlConfig, null, searchBaseConfig,
                         bindDnConfig));
@@ -226,7 +226,7 @@ private LDAPConfigResponse createLDAPConfigResponse(String hostname, Integer por
     }
 
     private boolean updateLDAP() {
-        _ldapManager.addConfiguration(hostname, port);
+        _ldapManager.addConfiguration(hostname, port, null);
 
         /**
          * There is no query filter now. It is derived from ldap.user.object and ldap.search.group.principle
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LDAPRemoveCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LDAPRemoveCmd.java
index eb3729d9d9e..0a4dc20ee0b 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LDAPRemoveCmd.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LDAPRemoveCmd.java
@@ -35,7 +35,7 @@
  * @deprecated as of 4.3 use the new api {@link LdapDeleteConfigurationCmd}
  */
 @Deprecated
-@APICommand(name = "ldapRemove", description = "Remove the LDAP context for this site.", responseObject = LDAPConfigResponse.class, since = "3.0.1",
+@APICommand(name = "ldapRemove", description = "(Deprecated , use deleteLdapConfiguration) Remove the LDAP context for this site.", responseObject = LDAPConfigResponse.class, since = "3.0.1",
         requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
 public class LDAPRemoveCmd extends BaseCmd {
     public static final Logger s_logger = Logger.getLogger(LDAPRemoveCmd.class.getName());
@@ -60,7 +60,7 @@ private boolean removeLDAP() {
         LdapListConfigurationCmd listConfigurationCmd = new LdapListConfigurationCmd(_ldapManager);
         Pair<List<? extends LdapConfigurationVO>, Integer> result = _ldapManager.listConfigurations(listConfigurationCmd);
         for (LdapConfigurationVO config : result.first()) {
-            _ldapManager.deleteConfiguration(config.getHostname());
+            _ldapManager.deleteConfiguration(config.getHostname(), 0, null);
         }
         return true;
     }
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapAddConfigurationCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapAddConfigurationCmd.java
index 555d1a987fd..7c592888364 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapAddConfigurationCmd.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapAddConfigurationCmd.java
@@ -18,6 +18,8 @@
 
 import javax.inject.Inject;
 
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.response.DomainResponse;
 import org.apache.log4j.Logger;
 
 import org.apache.cloudstack.api.APICommand;
@@ -40,12 +42,15 @@
     @Inject
     private LdapManager _ldapManager;
 
-    @Parameter(name = "hostname", type = CommandType.STRING, required = true, description = "Hostname")
+    @Parameter(name = ApiConstants.HOST_NAME, type = CommandType.STRING, required = true, description = "Hostname")
     private String hostname;
 
-    @Parameter(name = "port", type = CommandType.INTEGER, required = true, description = "Port")
+    @Parameter(name = ApiConstants.PORT, type = CommandType.INTEGER, required = true, description = "Port")
     private int port;
 
+    @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = false, entityType = DomainResponse.class, description = "linked domain")
+    private Long domainId;
+
     public LdapAddConfigurationCmd() {
         super();
     }
@@ -58,7 +63,7 @@ public LdapAddConfigurationCmd(final LdapManager ldapManager) {
     @Override
     public void execute() throws ServerApiException {
         try {
-            final LdapConfigurationResponse response = _ldapManager.addConfiguration(hostname, port);
+            final LdapConfigurationResponse response = _ldapManager.addConfiguration(hostname, port, domainId);
             response.setObjectName("LdapAddConfiguration");
             response.setResponseName(getCommandName());
             setResponseObject(response);
@@ -86,6 +91,10 @@ public int getPort() {
         return port;
     }
 
+    public Long getDomainId() {
+        return domainId;
+    }
+
     public void setHostname(final String hostname) {
         this.hostname = hostname;
     }
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java
index d845857925d..6e69259ebdd 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java
@@ -139,7 +139,7 @@ public void execute() throws ServerApiException {
         Long finalDomainId = getDomainId();
         callContext.setEventDetails("Account Name: " + finalAccountName + ", Domain Id:" + finalDomainId);
         try {
-            final LdapUser user = _ldapManager.getUser(username);
+            final LdapUser user = _ldapManager.getUser(username, domainId);
             validateUser(user);
             final UserAccount userAccount = createCloudstackUserAccount(user, finalAccountName, finalDomainId);
             if (userAccount != null) {
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapDeleteConfigurationCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapDeleteConfigurationCmd.java
index 30b37d8b88d..3ffebecfb95 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapDeleteConfigurationCmd.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapDeleteConfigurationCmd.java
@@ -18,6 +18,8 @@
 
 import javax.inject.Inject;
 
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.response.DomainResponse;
 import org.apache.log4j.Logger;
 
 import org.apache.cloudstack.api.APICommand;
@@ -40,9 +42,16 @@
     @Inject
     private LdapManager _ldapManager;
 
-    @Parameter(name = "hostname", type = CommandType.STRING, required = true, description = "Hostname")
+
+    @Parameter(name = ApiConstants.HOST_NAME, type = CommandType.STRING, required = true, description = "Hostname")
     private String hostname;
 
+    @Parameter(name = ApiConstants.PORT, type = CommandType.INTEGER, required = false, description = "port")
+    private int port;
+
+    @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = false, entityType = DomainResponse.class, description = "linked domain")
+    private Long domainId;
+
     public LdapDeleteConfigurationCmd() {
         super();
     }
@@ -52,10 +61,22 @@ public LdapDeleteConfigurationCmd(final LdapManager ldapManager) {
         _ldapManager = ldapManager;
     }
 
+    public String getHostname() {
+        return hostname;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public Long getDomainId() {
+        return domainId;
+    }
+
     @Override
     public void execute() throws ServerApiException {
         try {
-            final LdapConfigurationResponse response = _ldapManager.deleteConfiguration(hostname);
+            final LdapConfigurationResponse response = _ldapManager.deleteConfiguration(this);
             response.setObjectName("LdapDeleteConfiguration");
             response.setResponseName(getCommandName());
             setResponseObject(response);
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java
index 9fdd700638c..564c1d0a1ef 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java
@@ -142,9 +142,9 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE
         try {
             if (StringUtils.isNotBlank(groupName)) {
 
-                users = _ldapManager.getUsersInGroup(groupName);
+                users = _ldapManager.getUsersInGroup(groupName, domainId);
             } else {
-                users = _ldapManager.getUsers();
+                users = _ldapManager.getUsers(domainId);
             }
         } catch (NoLdapUserMatchingQueryException ex) {
             users = new ArrayList<LdapUser>();
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapListConfigurationCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapListConfigurationCmd.java
index 050fb36cb19..db6318e6b2c 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapListConfigurationCmd.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapListConfigurationCmd.java
@@ -21,6 +21,8 @@
 
 import javax.inject.Inject;
 
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.response.DomainResponse;
 import org.apache.log4j.Logger;
 
 import org.apache.cloudstack.api.APICommand;
@@ -44,12 +46,15 @@
     @Inject
     private LdapManager _ldapManager;
 
-    @Parameter(name = "hostname", type = CommandType.STRING, required = false, description = "Hostname")
+    @Parameter(name = ApiConstants. HOST_NAME, type = CommandType.STRING, required = false, description = "Hostname")
     private String hostname;
 
-    @Parameter(name = "port", type = CommandType.INTEGER, required = false, description = "Port")
+    @Parameter(name = ApiConstants.PORT, type = CommandType.INTEGER, required = false, description = "Port")
     private int port;
 
+    @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = false, entityType = DomainResponse.class, description = "linked domain")
+    private Long domainId;
+
     public LdapListConfigurationCmd() {
         super();
     }
@@ -97,6 +102,10 @@ public int getPort() {
         return port;
     }
 
+    public Long getDomainId() {
+        return domainId;
+    }
+
     public void setHostname(final String hostname) {
         this.hostname = hostname;
     }
@@ -104,4 +113,8 @@ public void setHostname(final String hostname) {
     public void setPort(final int port) {
         this.port = port;
     }
+
+    public void setDomainId(final Long domainId) {
+        this.domainId = domainId;
+    }
 }
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapListUsersCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapListUsersCmd.java
index e655f5f4ac0..b2266dc8fd3 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapListUsersCmd.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapListUsersCmd.java
@@ -83,7 +83,7 @@ public void execute() throws ServerApiException {
         List<LdapUserResponse> ldapResponses = null;
         final ListResponse<LdapUserResponse> response = new ListResponse<LdapUserResponse>();
         try {
-            final List<LdapUser> users = _ldapManager.getUsers();
+            final List<LdapUser> users = _ldapManager.getUsers(null);
             ldapResponses = createLdapUserResponse(users);
         } catch (final NoLdapUserMatchingQueryException ex) {
             ldapResponses = new ArrayList<LdapUserResponse>();
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LinkAccountToLdapCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LinkAccountToLdapCmd.java
new file mode 100644
index 00000000000..52adc664ff8
--- /dev/null
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LinkAccountToLdapCmd.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.cloudstack.api.command;
+
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.user.Account;
+import com.cloud.user.User;
+import com.cloud.user.UserAccount;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.DomainResponse;
+import org.apache.cloudstack.api.response.LinkAccountToLdapResponse;
+import org.apache.cloudstack.api.response.LinkDomainToLdapResponse;
+import org.apache.cloudstack.ldap.LdapManager;
+import org.apache.cloudstack.ldap.LdapUser;
+import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException;
+import org.apache.log4j.Logger;
+
+import javax.inject.Inject;
+import java.util.UUID;
+
+@APICommand(name = LinkAccountToLdapCmd.APINAME, description = "link a cloudstack account to a group or OU in ldap", responseObject = LinkDomainToLdapResponse.class, since = "4.11.0",
+    requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {RoleType.Admin,RoleType.DomainAdmin})
+public class LinkAccountToLdapCmd extends BaseCmd {
+    public static final Logger LOGGER = Logger.getLogger(LinkAccountToLdapCmd.class.getName());
+    public static final String APINAME = "linkAccountToLdap";
+
+    @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = true, entityType = DomainResponse.class, description = "The id of the domain that is to contain the linked account.")
+    private Long domainId;
+
+    @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, required = false, description = "type of the ldap name. GROUP or OU, defaults to GROUP")
+    private String type;
+
+    @Parameter(name = ApiConstants.LDAP_DOMAIN, type = CommandType.STRING, required = true, description = "name of the group or OU in LDAP")
+    private String ldapDomain;
+
+    @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, required = true, description = "name of the account, it will be created if it does not exist")
+    private String accountName;
+
+    @Parameter(name = ApiConstants.ADMIN, type = CommandType.STRING, required = false, description = "domain admin username in LDAP ")
+    private String admin;
+
+    @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, required = true, description = "Type of the account to auto import. Specify 0 for user and 2 for "
+            + "domain admin")
+    private short accountType;
+
+    @Inject
+    private LdapManager _ldapManager;
+
+    @Override
+    public void execute() throws ServerApiException {
+        try {
+            LinkAccountToLdapResponse response = _ldapManager.linkAccountToLdap(this);
+            if (admin != null) {
+                LdapUser ldapUser = null;
+                try {
+                    ldapUser = _ldapManager.getUser(admin, type, ldapDomain, domainId);
+                } catch (NoLdapUserMatchingQueryException e) {
+                    LOGGER.debug("no ldap user matching username " + admin + " in the given group/ou", e);
+                }
+                if (ldapUser != null && !ldapUser.isDisabled()) {
+                    Account account = _accountService.getActiveAccountByName(admin, domainId);
+                    if (account == null) {
+                        try {
+                            UserAccount userAccount = _accountService
+                                    .createUserAccount(admin, "", ldapUser.getFirstname(), ldapUser.getLastname(), ldapUser.getEmail(), null, admin, Account.ACCOUNT_TYPE_DOMAIN_ADMIN, RoleType.DomainAdmin.getId(), domainId, null, null, UUID.randomUUID().toString(),
+                                            UUID.randomUUID().toString(), User.Source.LDAP);
+                            response.setAdminId(String.valueOf(userAccount.getAccountId()));
+                            LOGGER.info("created an account with name " + admin + " in the given domain " + domainId);
+                        } catch (Exception e) {
+                            LOGGER.info("an exception occurred while creating account with name " + admin + " in domain " + domainId, e);
+                        }
+                    } else {
+                        LOGGER.debug("an account with name " + admin + " already exists in the domain " + domainId);
+                    }
+                } else {
+                    LOGGER.debug("ldap user with username " + admin + " is disabled in the given group/ou");
+                }
+            }
+            response.setObjectName(APINAME);
+            response.setResponseName(getCommandName());
+            setResponseObject(response);
+        } catch (final InvalidParameterValueException e) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.toString());
+        }
+    }
+
+    @Override
+    public String getCommandName() {
+        return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return Account.ACCOUNT_ID_SYSTEM;
+    }
+
+    public Long getDomainId() {
+        return domainId;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public String getLdapDomain() {
+        return ldapDomain;
+    }
+
+    public String getAccountName() {
+        return accountName;
+    }
+
+    public String getAdmin() {
+        return admin;
+    }
+
+    public short getAccountType() {
+        return accountType;
+    }
+}
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LinkDomainToLdapCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LinkDomainToLdapCmd.java
index 477e80f2556..00140952051 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LinkDomainToLdapCmd.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LinkDomainToLdapCmd.java
@@ -54,6 +54,10 @@
     @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, required = true, description = "type of the ldap name. GROUP or OU")
     private String type;
 
+    @Parameter(name = ApiConstants.LDAP_DOMAIN, type = CommandType.STRING, required = true, description = "name of the group or OU in LDAP")
+    private String ldapDomain;
+
+    @Deprecated
     @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "name of the group or OU in LDAP")
     private String name;
 
@@ -67,14 +71,35 @@
     @Inject
     private LdapManager _ldapManager;
 
+    public Long getDomainId() {
+        return domainId;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public String getLdapDomain() {
+        return ldapDomain == null ? name : ldapDomain;
+    }
+
+    public String getAdmin() {
+        return admin;
+    }
+
+    public short getAccountType() {
+        return accountType;
+    }
+
+
     @Override
     public void execute() throws ServerApiException {
         try {
-            LinkDomainToLdapResponse response = _ldapManager.linkDomainToLdap(domainId, type, name, accountType);
+            LinkDomainToLdapResponse response = _ldapManager.linkDomainToLdap(this);
             if(admin!=null) {
                 LdapUser ldapUser = null;
                 try {
-                    ldapUser = _ldapManager.getUser(admin, type, name);
+                    ldapUser = _ldapManager.getUser(admin, type, getLdapDomain(), domainId);
                 } catch (NoLdapUserMatchingQueryException e) {
                     s_logger.debug("no ldap user matching username " + admin + " in the given group/ou", e);
                 }
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LdapConfigurationResponse.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LdapConfigurationResponse.java
index a4e47828844..c6d2bf38cb2 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LdapConfigurationResponse.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LdapConfigurationResponse.java
@@ -18,31 +18,44 @@
 
 import com.google.gson.annotations.SerializedName;
 
+import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.BaseResponse;
 
 import com.cloud.serializer.Param;
+import org.apache.cloudstack.api.EntityReference;
+import org.apache.cloudstack.ldap.LdapConfiguration;
 
+@EntityReference(value = LdapConfiguration.class)
 public class LdapConfigurationResponse extends BaseResponse {
-    @SerializedName("hostname")
-    @Param(description = "hostname")
+    @SerializedName(ApiConstants.HOST_NAME)
+    @Param(description = "name of the host running the ldap server")
     private String hostname;
 
-    @SerializedName("port")
-    @Param(description = "port")
+    @SerializedName(ApiConstants.PORT)
+    @Param(description = "port teh ldap server is running on")
     private int port;
 
+    @SerializedName(ApiConstants.DOMAIN_ID)
+    @Param(description = "linked domain")
+    private String domainId;
+
     public LdapConfigurationResponse() {
         super();
     }
 
     public LdapConfigurationResponse(final String hostname) {
         super();
-        this.hostname = hostname;
+        setHostname(hostname);
     }
 
     public LdapConfigurationResponse(final String hostname, final int port) {
-        this.hostname = hostname;
-        this.port = port;
+        this(hostname);
+        setPort(port);
+    }
+
+    public LdapConfigurationResponse(final String hostname, final int port, final String domainId) {
+        this(hostname, port);
+        setDomainId(domainId);
     }
 
     public String getHostname() {
@@ -60,4 +73,12 @@ public void setHostname(final String hostname) {
     public void setPort(final int port) {
         this.port = port;
     }
+
+    public String getDomainId() {
+        return domainId;
+    }
+
+    public void setDomainId(String domainId) {
+        this.domainId = domainId;
+    }
 }
\ No newline at end of file
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LinkAccountToLdapResponse.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LinkAccountToLdapResponse.java
new file mode 100644
index 00000000000..23456e71641
--- /dev/null
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LinkAccountToLdapResponse.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.cloudstack.api.response;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+
+public class LinkAccountToLdapResponse extends BaseResponse {
+
+    @SerializedName(ApiConstants.DOMAIN_ID)
+    @Param(description = "id of the Domain which is linked to LDAP")
+    private String domainId;
+
+    @SerializedName(ApiConstants.LDAP_DOMAIN)
+    @Param(description = "name of the group or OU in LDAP which is linked to the domain")
+    private String ldapDomain;
+
+    @SerializedName(ApiConstants.TYPE)
+    @Param(description = "type of the name in LDAP which is linke to the domain")
+    private String type;
+
+    @SerializedName(ApiConstants.ACCOUNT_TYPE)
+    @Param(description = "Type of the account to auto import")
+    private short accountType;
+
+    @SerializedName(ApiConstants.ACCOUNT_ID)
+    @Param(description = "Domain Admin accountId that is created")
+    private String adminId;
+
+    @SerializedName(ApiConstants.ACCOUNT)
+    @Param(description = "name of the account")
+    private String accountName;
+
+
+    public LinkAccountToLdapResponse(String domainId, String type, String ldapDomain, short accountType, String adminId, String accountName) {
+        this.domainId = domainId;
+        this.type = type;
+        this.ldapDomain = ldapDomain;
+        this.accountType = accountType;
+        this.adminId = adminId;
+        this.accountName = accountName;
+    }
+
+    public String getDomainId() {
+        return domainId;
+    }
+
+    public String getLdapDomain() {
+        return ldapDomain;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public short getAccountType() {
+        return accountType;
+    }
+
+    public String getAdminId() {
+        return adminId;
+    }
+
+    public void setAdminId(String adminId) {
+        this.adminId = adminId;
+    }
+}
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LinkDomainToLdapResponse.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LinkDomainToLdapResponse.java
index 050eb6c3eb5..d6d4b55e257 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LinkDomainToLdapResponse.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LinkDomainToLdapResponse.java
@@ -66,11 +66,6 @@ public String getLdapDomain() {
         return ldapDomain == null ? name : ldapDomain;
     }
 
-    @Deprecated
-    public String getName() {
-        return ldapDomain == null ? name : ldapDomain;
-    }
-
     public String getType() {
         return type;
     }
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/ADLdapUserManagerImpl.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/ADLdapUserManagerImpl.java
index 0df638ad228..e844df57c1c 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/ADLdapUserManagerImpl.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/ADLdapUserManagerImpl.java
@@ -36,38 +36,38 @@
     private static final String MICROSOFT_AD_MEMBERS_FILTER = "memberOf";
 
     @Override
-    public List<LdapUser> getUsersInGroup(String groupName, LdapContext context) throws NamingException {
+    public List<LdapUser> getUsersInGroup(String groupName, LdapContext context, Long domainId) throws NamingException {
         if (StringUtils.isBlank(groupName)) {
             throw new IllegalArgumentException("ldap group name cannot be blank");
         }
 
-        String basedn = _ldapConfiguration.getBaseDn();
+        String basedn = _ldapConfiguration.getBaseDn(domainId);
         if (StringUtils.isBlank(basedn)) {
             throw new IllegalArgumentException("ldap basedn is not configured");
         }
 
         final SearchControls searchControls = new SearchControls();
         searchControls.setSearchScope(_ldapConfiguration.getScope());
-        searchControls.setReturningAttributes(_ldapConfiguration.getReturnAttributes());
+        searchControls.setReturningAttributes(_ldapConfiguration.getReturnAttributes(domainId));
 
-        NamingEnumeration<SearchResult> results = context.search(basedn, generateADGroupSearchFilter(groupName), searchControls);
+        NamingEnumeration<SearchResult> results = context.search(basedn, generateADGroupSearchFilter(groupName, domainId), searchControls);
         final List<LdapUser> users = new ArrayList<LdapUser>();
         while (results.hasMoreElements()) {
             final SearchResult result = results.nextElement();
-            users.add(createUser(result));
+            users.add(createUser(result, domainId));
         }
         return users;
     }
 
-    private String generateADGroupSearchFilter(String groupName) {
+    private String generateADGroupSearchFilter(String groupName, Long domainId) {
         final StringBuilder userObjectFilter = new StringBuilder();
         userObjectFilter.append("(objectClass=");
-        userObjectFilter.append(_ldapConfiguration.getUserObject());
+        userObjectFilter.append(_ldapConfiguration.getUserObject(domainId));
         userObjectFilter.append(")");
 
         final StringBuilder memberOfFilter = new StringBuilder();
-        String groupCnName =  _ldapConfiguration.getCommonNameAttribute() + "=" +groupName + "," +  _ldapConfiguration.getBaseDn();
-        memberOfFilter.append("(").append(getMemberOfAttribute()).append("=");
+        String groupCnName =  _ldapConfiguration.getCommonNameAttribute() + "=" +groupName + "," +  _ldapConfiguration.getBaseDn(domainId);
+        memberOfFilter.append("(").append(getMemberOfAttribute(domainId)).append("=");
         memberOfFilter.append(groupCnName);
         memberOfFilter.append(")");
 
@@ -94,8 +94,8 @@ protected boolean isUserDisabled(SearchResult result) throws NamingException {
         return isDisabledUser;
     }
 
-    protected String getMemberOfAttribute() {
-        if(_ldapConfiguration.isNestedGroupsEnabled()) {
+    protected String getMemberOfAttribute(final Long domainId) {
+        if(_ldapConfiguration.isNestedGroupsEnabled(domainId)) {
             return MICROSOFT_AD_NESTED_MEMBERS_FILTER;
         } else {
             return MICROSOFT_AD_MEMBERS_FILTER;
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java
index add39c5b13d..cd4ed3d5cea 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java
@@ -16,6 +16,8 @@
 // under the License.
 package org.apache.cloudstack.ldap;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
@@ -56,60 +58,181 @@ public LdapAuthenticator(final LdapManager ldapManager, final UserAccountDao use
 
     @Override
     public Pair<Boolean, ActionOnFailedAuthentication> authenticate(final String username, final String password, final Long domainId, final Map<String, Object[]> requestParameters) {
+        Pair<Boolean, ActionOnFailedAuthentication> rc = new Pair<Boolean, ActionOnFailedAuthentication>(false, null);
 
+        // TODO not allowing an empty password is a policy we shouldn't decide on. A private cloud may well want to allow this.
         if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
             s_logger.debug("Username or Password cannot be empty");
-            return new Pair<Boolean, ActionOnFailedAuthentication>(false, null);
+            return rc;
         }
 
-        boolean result = false;
-        ActionOnFailedAuthentication action = null;
-
         if (_ldapManager.isLdapEnabled()) {
             final UserAccount user = _userAccountDao.getUserAccount(username, domainId);
-            LdapTrustMapVO ldapTrustMapVO = _ldapManager.getDomainLinkedToLdap(domainId);
-            if(ldapTrustMapVO != null) {
-                try {
-                    LdapUser ldapUser = _ldapManager.getUser(username, ldapTrustMapVO.getType().toString(), ldapTrustMapVO.getName());
-                    if(!ldapUser.isDisabled()) {
-                        result = _ldapManager.canAuthenticate(ldapUser.getPrincipal(), password);
-                        if(result) {
-                            if(user == null) {
-                                // import user to cloudstack
-                                createCloudStackUserAccount(ldapUser, domainId, ldapTrustMapVO.getAccountType());
-                            } else {
-                                enableUserInCloudStack(user);
-                            }
-                        }
-                    } else {
-                        //disable user in cloudstack
-                        disableUserInCloudStack(user);
-                    }
-                } catch (NoLdapUserMatchingQueryException e) {
-                    s_logger.debug(e.getMessage());
+            List<LdapTrustMapVO> ldapTrustMapVOs = _ldapManager.getDomainLinkage(domainId);
+            if(ldapTrustMapVOs != null && ldapTrustMapVOs.size() > 0) {
+                if(ldapTrustMapVOs.size() == 1 && ldapTrustMapVOs.get(0).getAccountId() == 0) {
+                    // We have a single mapping of a domain to an ldap group or ou
+                    return authenticate(username, password, domainId, user, ldapTrustMapVOs.get(0));
+                } else {
+                    // we are dealing with mapping of accounts in a domain to ldap groups
+                    return authenticate(username, password, domainId, user, ldapTrustMapVOs);
                 }
-
             } else {
                 //domain is not linked to ldap follow normal authentication
-                if(user != null ) {
-                    try {
-                        LdapUser ldapUser = _ldapManager.getUser(username);
-                        if(!ldapUser.isDisabled()) {
-                            result = _ldapManager.canAuthenticate(ldapUser.getPrincipal(), password);
-                        } else {
-                            s_logger.debug("user with principal "+ ldapUser.getPrincipal() + " is disabled in ldap");
-                        }
-                    } catch (NoLdapUserMatchingQueryException e) {
-                        s_logger.debug(e.getMessage());
+                return authenticate(username, password, domainId, user);
+            }
+        }
+
+        return rc;
+    }
+
+    /**
+     * checks if the user exists in ldap and create in cloudstack if needed.
+     *
+     * @param username login id
+     * @param password pass phrase
+     * @param domainId domain the user is trying to log on to
+     * @param userAccount cloudstack user object
+     * @param ldapTrustMapVOs the trust mappings of accounts in the domain to ldap groups
+     * @return false if the ldap user object does not exist, is not mapped to an account, is mapped to multiple accounts or if authenitication fails
+     */
+    private Pair<Boolean, ActionOnFailedAuthentication> authenticate(String username, String password, Long domainId, UserAccount userAccount, List<LdapTrustMapVO> ldapTrustMapVOs) {
+        Pair<Boolean, ActionOnFailedAuthentication> rc = new Pair<Boolean, ActionOnFailedAuthentication>(false, null);
+        try {
+            LdapUser ldapUser = _ldapManager.getUser(username, domainId);
+            List<String> memberships = ldapUser.getMemberships();
+            List<String> mappedGroups = getMappedGroups(ldapTrustMapVOs);
+            mappedGroups.retainAll(memberships);
+            // check membership, there must be only one match in this domain
+            if(ldapUser.isDisabled()) {
+                logAndDisable(userAccount, "attempt to log on using disabled ldap user " + userAccount.getUsername(), false);
+            } else if(mappedGroups.size() > 1) {
+                logAndDisable(userAccount, "user '" + username + "' is mapped to more then one account in domain and will be disabled.", false);
+            } else if(mappedGroups.size() < 1) {
+                logAndDisable(userAccount, "user '" + username + "' is not mapped to an account in domain and will be removed.", true);
+            } else {
+                // a valid ldap configured user exists
+                LdapTrustMapVO mapping = _ldapManager.getLinkedLdapGroup(domainId,mappedGroups.get(0));
+                // we could now assert that ldapTrustMapVOs.contains(mapping);
+                // createUser in Account can only be done by account name not by account id
+                String accountName = _accountManager.getAccount(mapping.getAccountId()).getAccountName();
+                rc.first(_ldapManager.canAuthenticate(ldapUser.getPrincipal(), password, domainId));
+                // for security reasons we keep processing on faulty login attempt to not give a way information on userid existence
+                if (userAccount == null) {
+                    // new user that is in ldap; authenticate and create
+                    User user = _accountManager.createUser(username, "", ldapUser.getFirstname(), ldapUser.getLastname(), ldapUser.getEmail(), null, accountName,
+                            domainId, UUID.randomUUID().toString(), User.Source.LDAP);
+                    /* expected error conditions:
+                     *
+                     * caught in APIServlet: CloudRuntimeException("The domain " + domainId + " does not exist; unable to create user");
+                     * caught in APIServlet: CloudRuntimeException("The user cannot be created as domain " + domain.getName() + " is being deleted");
+                     * would have been thrown above: InvalidParameterValueException("Unable to find account " + accountName + " in domain id=" + domainId + " to create user");
+                     * we are system user: PermissionDeniedException("Account id : " + account.getId() + " is a system account, can't add a user to it");
+                     * serious and must be thrown: CloudRuntimeException("The user " + userName + " already exists in domain " + domainId);
+                     * fatal system error and must be thrown: CloudRuntimeException("Failed to encode password");
+                     */
+                    userAccount = _accountManager.getUserAccountById(user.getId());
+                } else {
+                    // not a new user, check if mapped group has changed
+                    if(userAccount.getAccountId() != mapping.getAccountId()) {
+                        _accountManager.moveUser(userAccount.getId(),userAccount.getDomainId(),mapping.getAccountId());
                     }
+                    // else { the user hasn't changed in ldap, the ldap group stayed the same, hurray, pass, fun thou self a lot of fun }
                 }
             }
-            if (!result && user != null) {
-                action = ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT;
+        } catch (NoLdapUserMatchingQueryException e) {
+            s_logger.debug(e.getMessage());
+            disableUserInCloudStack(userAccount);
+        }
+
+        return rc;
+    }
+
+    private void logAndDisable(UserAccount userAccount, String msg, boolean remove) {
+        if (s_logger.isInfoEnabled()) {
+            s_logger.info(msg);
+        }
+        if(remove) {
+            removeUserInCloudStack(userAccount);
+        } else {
+            disableUserInCloudStack(userAccount);
+        }
+    }
+
+    private List<String> getMappedGroups(List<LdapTrustMapVO> ldapTrustMapVOs) {
+        List<String> groups = new ArrayList<>();
+        for (LdapTrustMapVO vo : ldapTrustMapVOs) {
+            groups.add(vo.getName());
+        }
+        return groups;
+    }
+
+    /**
+     * checks if the user exists in ldap and create in cloudstack if needed
+     * @param username login id
+     * @param password pass phrase
+     * @param domainId domain the user is trying to log on to
+     * @param user cloudstack user object
+     * @param ldapTrustMapVO the trust mapping for the domain to the ldap group
+     * @return false if the ldap user object does not exist or authenitication fails
+     */
+    private Pair<Boolean, ActionOnFailedAuthentication> authenticate(String username, String password, Long domainId, UserAccount user, LdapTrustMapVO ldapTrustMapVO) {
+        Pair<Boolean, ActionOnFailedAuthentication> rc = new Pair<Boolean, ActionOnFailedAuthentication>(false, null);
+        try {
+            LdapUser ldapUser = _ldapManager.getUser(username, ldapTrustMapVO.getType().toString(), ldapTrustMapVO.getName(), domainId);
+            final short accountType = ldapTrustMapVO.getAccountType();
+            processLdapUser(password, domainId, user, rc, ldapUser, accountType);
+        } catch (NoLdapUserMatchingQueryException e) {
+            s_logger.debug(e.getMessage());
+        }
+        return rc;
+    }
+
+    private void processLdapUser(String password, Long domainId, UserAccount user, Pair<Boolean, ActionOnFailedAuthentication> rc, LdapUser ldapUser, short accountType) {
+        if(!ldapUser.isDisabled()) {
+            rc.first(_ldapManager.canAuthenticate(ldapUser.getPrincipal(), password, domainId));
+            if(rc.first()) {
+                if(user == null) {
+                    // import user to cloudstack
+                    createCloudStackUserAccount(ldapUser, domainId, accountType);
+                } else {
+                    enableUserInCloudStack(user);
+                }
+            } else if(user != null) {
+                rc.second(ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT);
             }
+        } else {
+            //disable user in cloudstack
+            disableUserInCloudStack(user);
         }
+    }
+
+    /**
+     * checks if the user is configured both in ldap and in cloudstack.
+     * @param username login id
+     * @param password pass phrase
+     * @param domainId domain the user is trying to log on to
+     * @param user cloudstack user object
+     * @return false if either user object does not exist or authenitication fails
+     */
+    private Pair<Boolean, ActionOnFailedAuthentication> authenticate(String username, String password, Long domainId, UserAccount user) {
+        boolean result = false;
 
-        return new Pair<Boolean, ActionOnFailedAuthentication>(result, action);
+        if(user != null ) {
+            try {
+                LdapUser ldapUser = _ldapManager.getUser(username, domainId);
+                if(!ldapUser.isDisabled()) {
+                    result = _ldapManager.canAuthenticate(ldapUser.getPrincipal(), password, domainId);
+                } else {
+                    s_logger.debug("user with principal "+ ldapUser.getPrincipal() + " is disabled in ldap");
+                }
+            } catch (NoLdapUserMatchingQueryException e) {
+                s_logger.debug(e.getMessage());
+            }
+        }
+        return (!result && user != null) ?
+                new Pair<Boolean, ActionOnFailedAuthentication>(false, ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT):
+                new Pair<Boolean, ActionOnFailedAuthentication>(false, null);
     }
 
     private void enableUserInCloudStack(UserAccount user) {
@@ -131,6 +254,12 @@ private void disableUserInCloudStack(UserAccount user) {
         }
     }
 
+    private void removeUserInCloudStack(UserAccount user) {
+        if (user != null) {
+            _accountManager.disableUser(user.getId());
+        }
+    }
+
     @Override
     public String encode(final String password) {
         return password;
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapConfiguration.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapConfiguration.java
index 56b39a8b3d1..22f8abc9aa5 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapConfiguration.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapConfiguration.java
@@ -31,75 +31,215 @@
 public class LdapConfiguration implements Configurable{
     private final static String factory = "com.sun.jndi.ldap.LdapCtxFactory";
 
-    private static final ConfigKey<Long> ldapReadTimeout = new ConfigKey<Long>(Long.class, "ldap.read.timeout", "Advanced", "1000",
-        "LDAP connection Timeout in milli sec", true, ConfigKey.Scope.Global, 1l);
-
-    private static final ConfigKey<Integer> ldapPageSize = new ConfigKey<Integer>(Integer.class, "ldap.request.page.size", "Advanced", "1000",
-                                                                               "page size sent to ldap server on each request to get user", true, ConfigKey.Scope.Global, 1);
-    private static final ConfigKey<String> ldapProvider = new ConfigKey<String>(String.class, "ldap.provider", "Advanced", "openldap", "ldap provider ex:openldap, microsoftad",
-                                                                                true, ConfigKey.Scope.Global, null);
-
-    private static final ConfigKey<Boolean> ldapEnableNestedGroups = new ConfigKey<Boolean>(Boolean.class, "ldap.nested.groups.enable", "Advanced", "true",
-                                                                                            "if true, nested groups will also be queried", true, ConfigKey.Scope.Global, null);
+    private static final ConfigKey<Long> ldapReadTimeout = new ConfigKey<Long>(
+            Long.class,
+            "ldap.read.timeout",
+            "Advanced",
+            "1000",
+            "LDAP connection Timeout in milli sec",
+            true,
+            ConfigKey.Scope.Domain,
+            1l);
+
+    private static final ConfigKey<Integer> ldapPageSize = new ConfigKey<Integer>(
+            Integer.class,
+            "ldap.request.page.size",
+            "Advanced",
+            "1000",
+            "page size sent to ldap server on each request to get user",
+            true,
+            ConfigKey.Scope.Domain,
+            1);
+
+    private static final ConfigKey<Boolean> ldapEnableNestedGroups = new ConfigKey<Boolean>(
+            "Advanced",
+            Boolean.class,
+            "ldap.nested.groups.enable",
+            "true",
+            "if true, nested groups will also be queried",
+            true,
+            ConfigKey.Scope.Domain);
+
+    private static final ConfigKey<String> ldapMemberOfAttribute = new ConfigKey<String>(
+            "Advanced",
+            String.class,
+            "ldap.user.memberof.attribute",
+            "memberof",
+            "the reverse membership attibute for group members",
+            true,
+            ConfigKey.Scope.Domain);
+
+    private static final ConfigKey<String> ldapProvider = new ConfigKey<String>(
+            "Advanced",
+            String.class,
+            "ldap.provider",
+            "openldap",
+            "ldap provider ex:openldap, microsoftad",
+            true,
+            ConfigKey.Scope.Domain);
+
+    private static final ConfigKey<String> ldapBaseDn = new ConfigKey<String>(
+            "Advanced",
+            String.class,
+            "ldap.basedn",
+            null,
+            "Sets the basedn for LDAP",
+            true,
+            ConfigKey.Scope.Domain);
+
+    private static final ConfigKey<String> ldapBindPassword = new ConfigKey<String>(
+            "Advanced",
+            String.class,
+            "ldap.bind.password",
+            null,
+            "Sets the bind password for LDAP",
+            true,
+            ConfigKey.Scope.Domain);
+    private static final ConfigKey<String> ldapBindPrincipal = new ConfigKey<String>(
+            "Advanced",
+            String.class,
+            "ldap.bind.principal",
+            null,
+            "Sets the bind principal for LDAP",
+            true,
+            ConfigKey.Scope.Domain);
+    private static final ConfigKey<String> ldapEmailAttribute = new ConfigKey<String>(
+            "Advanced",
+            String.class,
+            "ldap.email.attribute",
+            "mail",
+            "Sets the email attribute used within LDAP",
+            true,
+            ConfigKey.Scope.Domain);
+    private static final ConfigKey<String> ldapFirstnameAttribute = new ConfigKey<String>(
+            "Advanced",
+            String.class,
+            "ldap.firstname.attribute",
+            "givenname",
+            "Sets the firstname attribute used within LDAP",
+            true,
+            ConfigKey.Scope.Domain);
+    private static final ConfigKey<String> ldapLastnameAttribute = new ConfigKey<String>(
+            "Advanced",
+            String.class, "ldap.lastname.attribute",
+            "sn",
+            "Sets the lastname attribute used within LDAP",
+            true,
+            ConfigKey.Scope.Domain);
+    private static final ConfigKey<String> ldapUsernameAttribute = new ConfigKey<String>(
+            "Advanced",
+            String.class,
+            "ldap.username.attribute",
+            "uid",
+            "Sets the username attribute used within LDAP",
+            true,
+            ConfigKey.Scope.Domain);
+    private static final ConfigKey<String> ldapUserObject = new ConfigKey<String>(
+            "Advanced",
+            String.class,
+            "ldap.user.object",
+            "inetOrgPerson",
+            "Sets the object type of users within LDAP",
+            true,
+            ConfigKey.Scope.Domain);
+    private static final ConfigKey<String> ldapSearchGroupPrinciple = new ConfigKey<String>(
+            "Advanced",
+            String.class,
+            "ldap.search.group.principle",
+            null,
+            "Sets the principle of the group that users must be a member of",
+            true,
+            ConfigKey.Scope.Domain);
+    private static final ConfigKey<String> ldapGroupObject = new ConfigKey<String>(
+            "Advanced",
+            String.class,
+            "ldap.group.object",
+            "groupOfUniqueNames",
+            "Sets the object type of groups within LDAP",
+            true,
+            ConfigKey.Scope.Domain);
+    private static final ConfigKey<String> ldapGroupUniqueMemberAttribute = new ConfigKey<String>(
+            "Advanced",
+            String.class,
+            "ldap.group.user.uniquemember",
+            "uniquemember",
+            "Sets the attribute for uniquemembers within a group",
+            true,
+            ConfigKey.Scope.Domain);
+
+    private static final ConfigKey<String> ldapTrustStore = new ConfigKey<String>(
+            "Advanced",
+            String.class,
+            "ldap.truststore",
+            null,
+            "Sets the path to the truststore to use for SSL",
+            true,
+            ConfigKey.Scope.Domain);
+    private static final ConfigKey<String> ldapTrustStorePassword = new ConfigKey<String>(
+            "Advanced",
+            String.class,
+            "ldap.truststore.password",
+            null,
+            "Sets the password for the truststore",
+            true,
+            ConfigKey.Scope.Domain);
 
     private final static int scope = SearchControls.SUBTREE_SCOPE;
 
-    @Inject
-    private ConfigurationDao _configDao;
-
     @Inject
     private LdapConfigurationDao _ldapConfigurationDao;
 
     public LdapConfiguration() {
     }
 
+    public LdapConfiguration(final LdapConfigurationDao ldapConfigurationDao) {
+        _ldapConfigurationDao = ldapConfigurationDao;
+    }
+
+    @Deprecated
     public LdapConfiguration(final ConfigurationDao configDao, final LdapConfigurationDao ldapConfigurationDao) {
-        _configDao = configDao;
         _ldapConfigurationDao = ldapConfigurationDao;
     }
 
-    public String getAuthentication() {
-        if ((getBindPrincipal() == null) && (getBindPassword() == null)) {
+    public String getAuthentication(final Long domainId) {
+        if ((getBindPrincipal(domainId) == null) && (getBindPassword(domainId) == null)) {
             return "none";
         } else {
             return "simple";
         }
     }
 
-    public String getBaseDn() {
-        return _configDao.getValue("ldap.basedn");
+    public String getBaseDn(final Long domainId) {
+        return ldapBaseDn.valueIn(domainId);
     }
 
-    public String getBindPassword() {
-        return _configDao.getValue("ldap.bind.password");
+    public String getBindPassword(final Long domainId) {
+        return ldapBindPassword.valueIn(domainId);
     }
 
-    public String getBindPrincipal() {
-        return _configDao.getValue("ldap.bind.principal");
+    public String getBindPrincipal(final Long domainId) {
+        return ldapBindPrincipal.valueIn(domainId);
     }
 
-    public String getEmailAttribute() {
-        final String emailAttribute = _configDao.getValue("ldap.email.attribute");
-        return emailAttribute == null ? "mail" : emailAttribute;
+    public String getEmailAttribute(final Long domainId) {
+        return ldapEmailAttribute.valueIn(domainId);
     }
 
     public String getFactory() {
         return factory;
     }
 
-    public String getFirstnameAttribute() {
-        final String firstnameAttribute = _configDao.getValue("ldap.firstname.attribute");
-        return firstnameAttribute == null ? "givenname" : firstnameAttribute;
+    public String getFirstnameAttribute(final Long domainId) {
+        return ldapFirstnameAttribute.valueIn(domainId);
     }
 
-    public String getLastnameAttribute() {
-        final String lastnameAttribute = _configDao.getValue("ldap.lastname.attribute");
-        return lastnameAttribute == null ? "sn" : lastnameAttribute;
+    public String getLastnameAttribute(final Long domainId) {
+        return ldapLastnameAttribute.valueIn(domainId);
     }
 
-    public String getProviderUrl() {
+    public String getProviderUrl(final Long domainId) {
         final String protocol = getSSLStatus() == true ? "ldaps://" : "ldap://";
-        final Pair<List<LdapConfigurationVO>, Integer> result = _ldapConfigurationDao.searchConfigurations(null, 0);
+        final Pair<List<LdapConfigurationVO>, Integer> result = _ldapConfigurationDao.searchConfigurations(null, 0, domainId);
         final StringBuilder providerUrls = new StringBuilder();
         String delim = "";
         for (final LdapConfigurationVO resource : result.first()) {
@@ -110,17 +250,24 @@ public String getProviderUrl() {
         return providerUrls.toString();
     }
 
-    public String[] getReturnAttributes() {
-        return new String[] {getUsernameAttribute(), getEmailAttribute(), getFirstnameAttribute(), getLastnameAttribute(), getCommonNameAttribute(),
-                getUserAccountControlAttribute()};
+    public String[] getReturnAttributes(final Long domainId) {
+        return new String[] {
+                getUsernameAttribute(domainId),
+                getEmailAttribute(domainId),
+                getFirstnameAttribute(domainId),
+                getLastnameAttribute(domainId),
+                getCommonNameAttribute(),
+                getUserAccountControlAttribute(),
+                getUserMemberOfAttribute(domainId)
+        };
     }
 
     public int getScope() {
         return scope;
     }
 
-    public String getSearchGroupPrinciple() {
-        return _configDao.getValue("ldap.search.group.principle");
+    public String getSearchGroupPrinciple(final Long domainId) {
+        return ldapSearchGroupPrinciple.valueIn(domainId);
     }
 
     public boolean getSSLStatus() {
@@ -132,53 +279,51 @@ public boolean getSSLStatus() {
     }
 
     public String getTrustStore() {
-        return _configDao.getValue("ldap.truststore");
+        return ldapTrustStore.value();
     }
 
     public String getTrustStorePassword() {
-        return _configDao.getValue("ldap.truststore.password");
+        return ldapTrustStorePassword.value();
     }
 
-    public String getUsernameAttribute() {
-        final String usernameAttribute = _configDao.getValue("ldap.username.attribute");
-        return usernameAttribute == null ? "uid" : usernameAttribute;
+    public String getUsernameAttribute(final Long domainId) {
+        return ldapUsernameAttribute.valueIn(domainId);
     }
 
-    public String getUserObject() {
-        final String userObject = _configDao.getValue("ldap.user.object");
-        return userObject == null ? "inetOrgPerson" : userObject;
+    public String getUserObject(final Long domainId) {
+        return ldapUserObject.valueIn(domainId);
     }
 
-    public String getGroupObject() {
-        final String groupObject = _configDao.getValue("ldap.group.object");
-        return groupObject == null ? "groupOfUniqueNames" : groupObject;
+    public String getGroupObject(final Long domainId) {
+        return ldapGroupObject.valueIn(domainId);
     }
 
-    public String getGroupUniqueMemeberAttribute() {
-        final String uniqueMemberAttribute = _configDao.getValue("ldap.group.user.uniquemember");
-        return uniqueMemberAttribute == null ? "uniquemember" : uniqueMemberAttribute;
+    public String getGroupUniqueMemberAttribute(final Long domainId) {
+        return ldapGroupUniqueMemberAttribute.valueIn(domainId);
     }
 
+    // TODO remove hard-coding
     public String getCommonNameAttribute() {
         return "cn";
     }
 
+    // TODO remove hard-coding
     public String getUserAccountControlAttribute() {
         return "userAccountControl";
     }
 
-    public Long getReadTimeout() {
-        return ldapReadTimeout.value();
+    public Long getReadTimeout(final Long domainId) {
+        return ldapReadTimeout.valueIn(domainId);
     }
 
-    public Integer getLdapPageSize() {
-        return ldapPageSize.value();
+    public Integer getLdapPageSize(final Long domainId) {
+        return ldapPageSize.valueIn(domainId);
     }
 
-    public LdapUserManager.Provider getLdapProvider() {
+    public LdapUserManager.Provider getLdapProvider(final Long domainId) {
         LdapUserManager.Provider provider;
         try {
-            provider = LdapUserManager.Provider.valueOf(ldapProvider.value().toUpperCase());
+            provider = LdapUserManager.Provider.valueOf(ldapProvider.valueIn(domainId).toUpperCase());
         } catch (IllegalArgumentException ex) {
             //openldap is the default
             provider = LdapUserManager.Provider.OPENLDAP;
@@ -186,8 +331,12 @@ public Integer getLdapPageSize() {
         return provider;
     }
 
-    public boolean isNestedGroupsEnabled() {
-        return ldapEnableNestedGroups.value();
+    public boolean isNestedGroupsEnabled(final Long domainId) {
+        return ldapEnableNestedGroups.valueIn(domainId);
+    }
+
+    public static String getUserMemberOfAttribute(final Long domainId) {
+        return ldapMemberOfAttribute.valueIn(domainId);
     }
 
     @Override
@@ -197,6 +346,25 @@ public String getConfigComponentName() {
 
     @Override
     public ConfigKey<?>[] getConfigKeys() {
-        return new ConfigKey<?>[] {ldapReadTimeout, ldapPageSize, ldapProvider, ldapEnableNestedGroups};
+        return new ConfigKey<?>[]{
+                ldapReadTimeout,
+                ldapPageSize,
+                ldapProvider,
+                ldapEnableNestedGroups,
+                ldapBaseDn,
+                ldapBindPassword,
+                ldapBindPrincipal,
+                ldapEmailAttribute,
+                ldapFirstnameAttribute,
+                ldapLastnameAttribute,
+                ldapUsernameAttribute,
+                ldapUserObject,
+                ldapSearchGroupPrinciple,
+                ldapGroupObject,
+                ldapGroupUniqueMemberAttribute,
+                ldapTrustStore,
+                ldapTrustStorePassword,
+                ldapMemberOfAttribute
+        };
     }
-}
\ No newline at end of file
+}
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapConfigurationVO.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapConfigurationVO.java
index 488e7f44485..e7db88675ab 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapConfigurationVO.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapConfigurationVO.java
@@ -39,12 +39,16 @@
     @Column(name = "port")
     private int port;
 
+    @Column(name = "domain_id")
+    private Long domainId;
+
     public LdapConfigurationVO() {
     }
 
-    public LdapConfigurationVO(final String hostname, final int port) {
+    public LdapConfigurationVO(final String hostname, final int port, final Long domainId) {
         this.hostname = hostname;
         this.port = port;
+        this.domainId = domainId;
     }
 
     public String getHostname() {
@@ -60,6 +64,10 @@ public int getPort() {
         return port;
     }
 
+    public Long getDomainId() {
+        return domainId;
+    }
+
     public void setId(final long id) {
         this.id = id;
     }
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapContextFactory.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapContextFactory.java
index 9e27fff078e..b141f053008 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapContextFactory.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapContextFactory.java
@@ -40,29 +40,31 @@ public LdapContextFactory(final LdapConfiguration ldapConfiguration) {
         _ldapConfiguration = ldapConfiguration;
     }
 
-    public LdapContext createBindContext() throws NamingException, IOException {
-        return createBindContext(null);
+    // TODO add optional domain (optional only for backwards compatibility)
+    public LdapContext createBindContext(Long domainId) throws NamingException, IOException {
+        return createBindContext(null, domainId);
     }
 
-    public LdapContext createBindContext(final String providerUrl) throws NamingException, IOException {
-        final String bindPrincipal = _ldapConfiguration.getBindPrincipal();
-        final String bindPassword = _ldapConfiguration.getBindPassword();
-        return createInitialDirContext(bindPrincipal, bindPassword, providerUrl, true);
+    // TODO add optional domain (optional only for backwards compatibility)
+    public LdapContext createBindContext(final String providerUrl, Long domainId) throws NamingException, IOException {
+        final String bindPrincipal = _ldapConfiguration.getBindPrincipal(domainId);
+        final String bindPassword = _ldapConfiguration.getBindPassword(domainId);
+        return createInitialDirContext(bindPrincipal, bindPassword, providerUrl, true, domainId);
     }
 
-    private LdapContext createInitialDirContext(final String principal, final String password, final boolean isSystemContext) throws NamingException, IOException {
-        return createInitialDirContext(principal, password, null, isSystemContext);
+    private LdapContext createInitialDirContext(final String principal, final String password, final boolean isSystemContext, Long domainId) throws NamingException, IOException {
+        return createInitialDirContext(principal, password, null, isSystemContext, domainId);
     }
 
-    private LdapContext createInitialDirContext(final String principal, final String password, final String providerUrl, final boolean isSystemContext)
+    private LdapContext createInitialDirContext(final String principal, final String password, final String providerUrl, final boolean isSystemContext, Long domainId)
         throws NamingException, IOException {
-        Hashtable<String, String> environment = getEnvironment(principal, password, providerUrl, isSystemContext);
+        Hashtable<String, String> environment = getEnvironment(principal, password, providerUrl, isSystemContext, domainId);
         s_logger.debug("initializing ldap with provider url: " + environment.get(Context.PROVIDER_URL));
         return new InitialLdapContext(environment, null);
     }
 
-    public LdapContext createUserContext(final String principal, final String password) throws NamingException, IOException {
-        return createInitialDirContext(principal, password, false);
+    public LdapContext createUserContext(final String principal, final String password, Long domainId) throws NamingException, IOException {
+        return createInitialDirContext(principal, password, false, domainId);
     }
 
     private void enableSSL(final Hashtable<String, String> environment) {
@@ -76,19 +78,19 @@ private void enableSSL(final Hashtable<String, String> environment) {
         }
     }
 
-    private Hashtable<String, String> getEnvironment(final String principal, final String password, final String providerUrl, final boolean isSystemContext) {
+    private Hashtable<String, String> getEnvironment(final String principal, final String password, final String providerUrl, final boolean isSystemContext, Long domainId) {
         final String factory = _ldapConfiguration.getFactory();
-        final String url = providerUrl == null ? _ldapConfiguration.getProviderUrl() : providerUrl;
+        final String url = providerUrl == null ? _ldapConfiguration.getProviderUrl(domainId) : providerUrl;
 
         final Hashtable<String, String> environment = new Hashtable<String, String>();
 
         environment.put(Context.INITIAL_CONTEXT_FACTORY, factory);
         environment.put(Context.PROVIDER_URL, url);
-        environment.put("com.sun.jndi.ldap.read.timeout", _ldapConfiguration.getReadTimeout().toString());
+        environment.put("com.sun.jndi.ldap.read.timeout", _ldapConfiguration.getReadTimeout(domainId).toString());
         environment.put("com.sun.jndi.ldap.connect.pool", "true");
 
         enableSSL(environment);
-        setAuthentication(environment, isSystemContext);
+        setAuthentication(environment, isSystemContext, domainId);
 
         if (principal != null) {
             environment.put(Context.SECURITY_PRINCIPAL, principal);
@@ -101,8 +103,8 @@ private void enableSSL(final Hashtable<String, String> environment) {
         return environment;
     }
 
-    private void setAuthentication(final Hashtable<String, String> environment, final boolean isSystemContext) {
-        final String authentication = _ldapConfiguration.getAuthentication();
+    private void setAuthentication(final Hashtable<String, String> environment, final boolean isSystemContext, final Long domainId) {
+        final String authentication = _ldapConfiguration.getAuthentication(domainId);
 
         if ("none".equals(authentication) && !isSystemContext) {
             environment.put(Context.SECURITY_AUTHENTICATION, "simple");
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapManager.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapManager.java
index 6af2c4ebd95..002242c8f02 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapManager.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapManager.java
@@ -18,36 +18,48 @@
 
 import java.util.List;
 
+import org.apache.cloudstack.api.command.LdapAddConfigurationCmd;
+import org.apache.cloudstack.api.command.LdapDeleteConfigurationCmd;
 import org.apache.cloudstack.api.command.LdapListConfigurationCmd;
+import org.apache.cloudstack.api.command.LinkAccountToLdapCmd;
+import org.apache.cloudstack.api.command.LinkDomainToLdapCmd;
 import org.apache.cloudstack.api.response.LdapConfigurationResponse;
 import org.apache.cloudstack.api.response.LdapUserResponse;
 
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.utils.Pair;
 import com.cloud.utils.component.PluggableService;
+import org.apache.cloudstack.api.response.LinkAccountToLdapResponse;
 import org.apache.cloudstack.api.response.LinkDomainToLdapResponse;
 
 public interface LdapManager extends PluggableService {
 
     enum LinkType { GROUP, OU;}
 
-    LdapConfigurationResponse addConfiguration(String hostname, int port) throws InvalidParameterValueException;
+    LdapConfigurationResponse addConfiguration(final LdapAddConfigurationCmd cmd) throws InvalidParameterValueException;
 
-    boolean canAuthenticate(String principal, String password);
+    @Deprecated
+    LdapConfigurationResponse addConfiguration(String hostname, int port, Long domainId) throws InvalidParameterValueException;
+
+    boolean canAuthenticate(String principal, String password, final Long domainId);
 
     LdapConfigurationResponse createLdapConfigurationResponse(LdapConfigurationVO configuration);
 
     LdapUserResponse createLdapUserResponse(LdapUser user);
 
-    LdapConfigurationResponse deleteConfiguration(String hostname) throws InvalidParameterValueException;
+    LdapConfigurationResponse deleteConfiguration(LdapDeleteConfigurationCmd cmd) throws InvalidParameterValueException;
+
+    @Deprecated
+    LdapConfigurationResponse deleteConfiguration(String hostname, int port, Long domainId) throws InvalidParameterValueException;
 
-    LdapUser getUser(final String username) throws NoLdapUserMatchingQueryException;
+    // TODO username is only unique withing domain scope (add domain id to call)
+    LdapUser getUser(final String username, Long domainId) throws NoLdapUserMatchingQueryException;
 
-    LdapUser getUser(String username, String type, String name) throws NoLdapUserMatchingQueryException;
+    LdapUser getUser(String username, String type, String name, Long domainId) throws NoLdapUserMatchingQueryException;
 
-    List<LdapUser> getUsers() throws NoLdapUserMatchingQueryException;
+    List<LdapUser> getUsers(Long domainId) throws NoLdapUserMatchingQueryException;
 
-    List<LdapUser> getUsersInGroup(String groupName) throws NoLdapUserMatchingQueryException;
+    List<LdapUser> getUsersInGroup(String groupName, Long domainId) throws NoLdapUserMatchingQueryException;
 
     boolean isLdapEnabled();
 
@@ -55,7 +67,15 @@
 
     List<LdapUser> searchUsers(String query) throws NoLdapUserMatchingQueryException;
 
-    LinkDomainToLdapResponse linkDomainToLdap(Long domainId, String type, String name, short accountType);
+    LinkDomainToLdapResponse linkDomainToLdap(LinkDomainToLdapCmd cmd);
+
+    LdapTrustMapVO getDomainLinkedToLdap(long domainId);
+
+    List<LdapTrustMapVO> getDomainLinkage(long domainId);
+
+    LdapTrustMapVO getAccountLinkedToLdap(long domainId, long accountId);
+
+    LdapTrustMapVO getLinkedLdapGroup(long domainId, String group);
 
-    public LdapTrustMapVO getDomainLinkedToLdap(long domainId);
+    LinkAccountToLdapResponse linkAccountToLdap(LinkAccountToLdapCmd linkAccountToLdapCmd);
 }
\ No newline at end of file
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapManagerImpl.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapManagerImpl.java
index beb7a61cd70..b82231c99d7 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapManagerImpl.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapManagerImpl.java
@@ -23,6 +23,7 @@
 import javax.inject.Inject;
 import javax.naming.NamingException;
 import javax.naming.ldap.LdapContext;
+import java.util.UUID;
 
 import org.apache.cloudstack.api.LdapValidator;
 import org.apache.cloudstack.api.command.LDAPConfigCmd;
@@ -34,9 +35,11 @@
 import org.apache.cloudstack.api.command.LdapListConfigurationCmd;
 import org.apache.cloudstack.api.command.LdapListUsersCmd;
 import org.apache.cloudstack.api.command.LdapUserSearchCmd;
+import org.apache.cloudstack.api.command.LinkAccountToLdapCmd;
 import org.apache.cloudstack.api.command.LinkDomainToLdapCmd;
 import org.apache.cloudstack.api.response.LdapConfigurationResponse;
 import org.apache.cloudstack.api.response.LdapUserResponse;
+import org.apache.cloudstack.api.response.LinkAccountToLdapResponse;
 import org.apache.cloudstack.api.response.LinkDomainToLdapResponse;
 import org.apache.cloudstack.ldap.dao.LdapConfigurationDao;
 import org.apache.cloudstack.ldap.dao.LdapTrustMapDao;
@@ -47,6 +50,9 @@
 import com.cloud.domain.DomainVO;
 import com.cloud.domain.dao.DomainDao;
 import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.user.Account;
+import com.cloud.user.AccountVO;
+import com.cloud.user.dao.AccountDao;
 import com.cloud.utils.Pair;
 
 @Component
@@ -59,6 +65,9 @@
     @Inject
     private DomainDao domainDao;
 
+    @Inject
+    private AccountDao accountDao;
+
     @Inject
     private LdapContextFactory _ldapContextFactory;
 
@@ -85,17 +94,32 @@ public LdapManagerImpl(final LdapConfigurationDao ldapConfigurationDao, final Ld
     }
 
     @Override
-    public LdapConfigurationResponse addConfiguration(final String hostname, final int port) throws InvalidParameterValueException {
-        LdapConfigurationVO configuration = _ldapConfigurationDao.findByHostname(hostname);
+    public LdapConfigurationResponse addConfiguration(final LdapAddConfigurationCmd cmd) throws InvalidParameterValueException {
+        return addConfigurationInternal(cmd.getHostname(),cmd.getPort(),cmd.getDomainId());
+    }
+
+    @Override // TODO make private
+    public LdapConfigurationResponse addConfiguration(final String hostname, int port, final Long domainId) throws InvalidParameterValueException {
+        return addConfigurationInternal(hostname,port,domainId);
+    }
+
+    private LdapConfigurationResponse addConfigurationInternal(final String hostname, int port, final Long domainId) throws InvalidParameterValueException {
+        // TODO evaluate what the right default should be
+        if(port <= 0) {
+            port = 389;
+        }
+
+        // hostname:port is unique for domain binding
+        LdapConfigurationVO configuration = _ldapConfigurationDao.find(hostname, port, domainId);
         if (configuration == null) {
             LdapContext context = null;
             try {
                 final String providerUrl = "ldap://" + hostname + ":" + port;
-                context = _ldapContextFactory.createBindContext(providerUrl);
-                configuration = new LdapConfigurationVO(hostname, port);
+                context = _ldapContextFactory.createBindContext(providerUrl,domainId);
+                configuration = new LdapConfigurationVO(hostname, port, domainId);
                 _ldapConfigurationDao.persist(configuration);
-                s_logger.info("Added new ldap server with hostname: " + hostname);
-                return new LdapConfigurationResponse(hostname, port);
+                s_logger.info("Added new ldap server with url: " + providerUrl + (domainId == null ? "": " for domain " + domainId));
+                return createLdapConfigurationResponse(configuration);
             } catch (NamingException | IOException e) {
                 s_logger.debug("NamingException while doing an LDAP bind", e);
                 throw new InvalidParameterValueException("Unable to bind to the given LDAP server");
@@ -107,10 +131,18 @@ public LdapConfigurationResponse addConfiguration(final String hostname, final i
         }
     }
 
+    /**
+     * TODO decide if the principal is good enough to get the domain id or we need to add it as parameter
+     * @param principal
+     * @param password
+     * @param domainId
+     * @return
+     */
     @Override
-    public boolean canAuthenticate(final String principal, final String password) {
+    public boolean canAuthenticate(final String principal, final String password, final Long domainId) {
         try {
-            final LdapContext context = _ldapContextFactory.createUserContext(principal, password);
+            // TODO return the right account for this user
+            final LdapContext context = _ldapContextFactory.createUserContext(principal, password,domainId);
             closeContext(context);
             return true;
         } catch (NamingException | IOException e) {
@@ -132,10 +164,11 @@ private void closeContext(final LdapContext context) {
 
     @Override
     public LdapConfigurationResponse createLdapConfigurationResponse(final LdapConfigurationVO configuration) {
-        final LdapConfigurationResponse response = new LdapConfigurationResponse();
-        response.setHostname(configuration.getHostname());
-        response.setPort(configuration.getPort());
-        return response;
+        String domainUuid = null;
+        if(configuration.getDomainId() != null) {
+            domainUuid = domainDao.findById(configuration.getDomainId()).getUuid();
+        }
+        return new LdapConfigurationResponse(configuration.getHostname(), configuration.getPort(), domainUuid);
     }
 
     @Override
@@ -151,14 +184,23 @@ public LdapUserResponse createLdapUserResponse(final LdapUser user) {
     }
 
     @Override
-    public LdapConfigurationResponse deleteConfiguration(final String hostname) throws InvalidParameterValueException {
-        final LdapConfigurationVO configuration = _ldapConfigurationDao.findByHostname(hostname);
+    public LdapConfigurationResponse deleteConfiguration(final LdapDeleteConfigurationCmd cmd) throws InvalidParameterValueException {
+        return deleteConfigurationInternal(cmd.getHostname(), cmd.getPort(), cmd.getDomainId());
+    }
+
+    @Override
+    public LdapConfigurationResponse deleteConfiguration(final String hostname, int port, Long domainId) throws InvalidParameterValueException {
+        return deleteConfigurationInternal(hostname, port, domainId);
+    }
+
+    private LdapConfigurationResponse deleteConfigurationInternal(final String hostname, int port, Long domainId) throws InvalidParameterValueException {
+        final LdapConfigurationVO configuration = _ldapConfigurationDao.find(hostname,port,domainId);
         if (configuration == null) {
             throw new InvalidParameterValueException("Cannot find configuration with hostname " + hostname);
         } else {
             _ldapConfigurationDao.remove(configuration.getId());
-            s_logger.info("Removed ldap server with hostname: " + hostname);
-            return new LdapConfigurationResponse(configuration.getHostname(), configuration.getPort());
+            s_logger.info("Removed ldap server with url: " + hostname + ':' + port + (domainId == null ? "" : " for domain id " + domainId));
+            return createLdapConfigurationResponse(configuration);
         }
     }
 
@@ -175,17 +217,18 @@ public LdapConfigurationResponse deleteConfiguration(final String hostname) thro
         cmdList.add(LDAPConfigCmd.class);
         cmdList.add(LDAPRemoveCmd.class);
         cmdList.add(LinkDomainToLdapCmd.class);
+        cmdList.add(LinkAccountToLdapCmd.class);
         return cmdList;
     }
 
     @Override
-    public LdapUser getUser(final String username) throws NoLdapUserMatchingQueryException {
+    public LdapUser getUser(final String username, Long domainId) throws NoLdapUserMatchingQueryException {
         LdapContext context = null;
         try {
-            context = _ldapContextFactory.createBindContext();
+            context = _ldapContextFactory.createBindContext(domainId);
 
             final String escapedUsername = LdapUtils.escapeLDAPSearchFilter(username);
-            return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider()).getUser(escapedUsername, context);
+            return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider(null)).getUser(escapedUsername, context, domainId);
 
         } catch (NamingException | IOException e) {
             s_logger.debug("ldap Exception: ",e);
@@ -196,26 +239,26 @@ public LdapUser getUser(final String username) throws NoLdapUserMatchingQueryExc
     }
 
     @Override
-    public LdapUser getUser(final String username, final String type, final String name) throws NoLdapUserMatchingQueryException {
+    public LdapUser getUser(final String username, final String type, final String name, Long domainId) throws NoLdapUserMatchingQueryException {
         LdapContext context = null;
         try {
-            context = _ldapContextFactory.createBindContext();
+            context = _ldapContextFactory.createBindContext(domainId);
             final String escapedUsername = LdapUtils.escapeLDAPSearchFilter(username);
-            return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider()).getUser(escapedUsername, type, name, context);
+            return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider(null)).getUser(escapedUsername, type, name, context, domainId);
         } catch (NamingException | IOException e) {
             s_logger.debug("ldap Exception: ",e);
-            throw new NoLdapUserMatchingQueryException("No Ldap User found for username: "+username + "name: " + name + "of type: " + type);
+            throw new NoLdapUserMatchingQueryException("No Ldap User found for username: "+username + " in group: " + name + " of type: " + type);
         } finally {
             closeContext(context);
         }
     }
 
     @Override
-    public List<LdapUser> getUsers() throws NoLdapUserMatchingQueryException {
+    public List<LdapUser> getUsers(Long domainId) throws NoLdapUserMatchingQueryException {
         LdapContext context = null;
         try {
-            context = _ldapContextFactory.createBindContext();
-            return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider()).getUsers(context);
+            context = _ldapContextFactory.createBindContext(domainId);
+            return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider(domainId)).getUsers(context, domainId);
         } catch (NamingException | IOException e) {
             s_logger.debug("ldap Exception: ",e);
             throw new NoLdapUserMatchingQueryException("*");
@@ -225,11 +268,11 @@ public LdapUser getUser(final String username, final String type, final String n
     }
 
     @Override
-    public List<LdapUser> getUsersInGroup(String groupName) throws NoLdapUserMatchingQueryException {
+    public List<LdapUser> getUsersInGroup(String groupName, Long domainId) throws NoLdapUserMatchingQueryException {
         LdapContext context = null;
         try {
-            context = _ldapContextFactory.createBindContext();
-            return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider()).getUsersInGroup(groupName, context);
+            context = _ldapContextFactory.createBindContext(domainId);
+            return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider(domainId)).getUsersInGroup(groupName, context, domainId);
         } catch (NamingException | IOException e) {
             s_logger.debug("ldap NamingException: ",e);
             throw new NoLdapUserMatchingQueryException("groupName=" + groupName);
@@ -247,7 +290,8 @@ public boolean isLdapEnabled() {
     public Pair<List<? extends LdapConfigurationVO>, Integer> listConfigurations(final LdapListConfigurationCmd cmd) {
         final String hostname = cmd.getHostname();
         final int port = cmd.getPort();
-        final Pair<List<LdapConfigurationVO>, Integer> result = _ldapConfigurationDao.searchConfigurations(hostname, port);
+        final Long domainId = cmd.getDomainId();
+        final Pair<List<LdapConfigurationVO>, Integer> result = _ldapConfigurationDao.searchConfigurations(hostname, port, domainId);
         return new Pair<List<? extends LdapConfigurationVO>, Integer>(result.first(), result.second());
     }
 
@@ -255,9 +299,10 @@ public boolean isLdapEnabled() {
     public List<LdapUser> searchUsers(final String username) throws NoLdapUserMatchingQueryException {
         LdapContext context = null;
         try {
-            context = _ldapContextFactory.createBindContext();
+            // TODO search users per domain (only?)
+            context = _ldapContextFactory.createBindContext(null);
             final String escapedUsername = LdapUtils.escapeLDAPSearchFilter(username);
-            return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider()).getUsers("*" + escapedUsername + "*", context);
+            return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider(null)).getUsers("*" + escapedUsername + "*", context, null);
         } catch (NamingException | IOException e) {
             s_logger.debug("ldap Exception: ",e);
             throw new NoLdapUserMatchingQueryException(username);
@@ -267,14 +312,20 @@ public boolean isLdapEnabled() {
     }
 
     @Override
-    public LinkDomainToLdapResponse linkDomainToLdap(Long domainId, String type, String name, short accountType) {
+    public LinkDomainToLdapResponse linkDomainToLdap(LinkDomainToLdapCmd cmd) {
+        Validate.isTrue(_ldapConfiguration.getBaseDn(cmd.getDomainId()) == null, "can not configure an ldap server and an ldap group/ou to a domain");
+        Validate.notEmpty(cmd.getLdapDomain(), "ldapDomain cannot be empty, please supply a GROUP or OU name");
+        return linkDomainToLdap(cmd.getDomainId(),cmd.getType(),cmd.getLdapDomain(),cmd.getAccountType());
+    }
+
+    private LinkDomainToLdapResponse linkDomainToLdap(Long domainId, String type, String name, short accountType) {
         Validate.notNull(type, "type cannot be null. It should either be GROUP or OU");
         Validate.notNull(domainId, "domainId cannot be null.");
         Validate.notEmpty(name, "GROUP or OU name cannot be empty");
         //Account type should be 0 or 2. check the constants in com.cloud.user.Account
         Validate.isTrue(accountType==0 || accountType==2, "accountype should be either 0(normal user) or 2(domain admin)");
         LinkType linkType = LdapManager.LinkType.valueOf(type.toUpperCase());
-        LdapTrustMapVO vo = _ldapTrustMapDao.persist(new LdapTrustMapVO(domainId, linkType, name, accountType));
+        LdapTrustMapVO vo = _ldapTrustMapDao.persist(new LdapTrustMapVO(domainId, linkType, name, accountType, 0));
         DomainVO domain = domainDao.findById(vo.getDomainId());
         String domainUuid = "<unknown>";
         if (domain == null) {
@@ -290,4 +341,46 @@ public LinkDomainToLdapResponse linkDomainToLdap(Long domainId, String type, Str
     public LdapTrustMapVO getDomainLinkedToLdap(long domainId){
         return _ldapTrustMapDao.findByDomainId(domainId);
     }
+
+    @Override
+    public List<LdapTrustMapVO> getDomainLinkage(long domainId){
+        return _ldapTrustMapDao.searchByDomainId(domainId);
+    }
+
+    public LdapTrustMapVO getAccountLinkedToLdap(long domainId, long accountId){
+        return _ldapTrustMapDao.findByAccount(domainId, accountId);
+    }
+
+    @Override
+    public LdapTrustMapVO getLinkedLdapGroup(long domainId, String group) {
+        return _ldapTrustMapDao.findGroupInDomain(domainId, group);
+    }
+
+    @Override public LinkAccountToLdapResponse linkAccountToLdap(LinkAccountToLdapCmd cmd) {
+        Validate.notNull(_ldapConfiguration.getBaseDn(cmd.getDomainId()), "can not configure an ldap server and an ldap group/ou to a domain");
+        Validate.notNull(cmd.getDomainId(), "domainId cannot be null.");
+        Validate.notEmpty(cmd.getAccountName(), "accountName cannot be empty.");
+        Validate.notEmpty(cmd.getLdapDomain(), "ldapDomain cannot be empty, please supply a GROUP or OU name");
+        Validate.notNull(cmd.getType(), "type cannot be null. It should either be GROUP or OU");
+        Validate.notEmpty(cmd.getLdapDomain(), "GROUP or OU name cannot be empty");
+
+        LinkType linkType = LdapManager.LinkType.valueOf(cmd.getType().toUpperCase());
+        Account account = accountDao.findActiveAccount(cmd.getAccountName(),cmd.getDomainId());
+        if (account == null) {
+            account = new AccountVO(cmd.getAccountName(), cmd.getDomainId(), null, cmd.getAccountType(), UUID.randomUUID().toString());
+            accountDao.persist((AccountVO)account);
+        }
+        Long accountId = account.getAccountId();
+        LdapTrustMapVO vo = _ldapTrustMapDao.persist(new LdapTrustMapVO(cmd.getDomainId(), linkType, cmd.getLdapDomain(), cmd.getAccountType(), accountId));
+        DomainVO domain = domainDao.findById(vo.getDomainId());
+        String domainUuid = "<unknown>";
+        if (domain == null) {
+            s_logger.error("no domain in database for id " + vo.getDomainId());
+        } else {
+            domainUuid = domain.getUuid();
+        }
+
+        LinkAccountToLdapResponse response = new LinkAccountToLdapResponse(domainUuid, vo.getType().toString(), vo.getName(), vo.getAccountType(), account.getUuid(), cmd.getAccountName());
+        return response;
+    }
 }
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapTrustMapVO.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapTrustMapVO.java
index 8b1363816fa..c402747b813 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapTrustMapVO.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapTrustMapVO.java
@@ -45,6 +45,9 @@
     @Column(name = "domain_id")
     private long domainId;
 
+    @Column(name = "account_id")
+    private long accountId;
+
     @Column(name = "account_type")
     private short accountType;
 
@@ -52,11 +55,12 @@
     public LdapTrustMapVO() {
     }
 
-    public LdapTrustMapVO(long domainId, LdapManager.LinkType type, String name, short accountType) {
+    public LdapTrustMapVO(long domainId, LdapManager.LinkType type, String name, short accountType, long accountId) {
         this.domainId = domainId;
         this.type = type;
         this.name = name;
         this.accountType = accountType;
+        this.accountId = accountId;
     }
 
     @Override
@@ -80,6 +84,10 @@ public short getAccountType() {
         return accountType;
     }
 
+    public long getAccountId() {
+        return accountId;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) {
@@ -94,6 +102,9 @@ public boolean equals(Object o) {
         if (domainId != that.domainId) {
             return false;
         }
+        if (accountId != that.accountId) {
+            return false;
+        }
         if (accountType != that.accountType) {
             return false;
         }
@@ -109,6 +120,7 @@ public int hashCode() {
         int result = type.hashCode();
         result = 31 * result + name.hashCode();
         result = 31 * result + (int) (domainId ^ (domainId >>> 32));
+        result = 31 * result + (int) (accountId ^ (accountId >>> 32));
         result = 31 * result + (int) accountType;
         return result;
     }
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapUser.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapUser.java
index c4c334b5b6e..064ee412ab4 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapUser.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapUser.java
@@ -16,6 +16,9 @@
 // under the License.
 package org.apache.cloudstack.ldap;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class LdapUser implements Comparable<LdapUser> {
     private final String email;
     private final String principal;
@@ -24,8 +27,10 @@
     private final String username;
     private final String domain;
     private final boolean disabled;
+    private List<String> memberships;
 
-    public LdapUser(final String username, final String email, final String firstname, final String lastname, final String principal, String domain, boolean disabled) {
+    public LdapUser(final String username, final String email, final String firstname, final String lastname, final String principal, String domain, boolean disabled,
+            List<String> memberships) {
         this.username = username;
         this.email = email;
         this.firstname = firstname;
@@ -33,6 +38,7 @@ public LdapUser(final String username, final String email, final String firstnam
         this.principal = principal;
         this.domain = domain;
         this.disabled = disabled;
+        this.memberships = memberships == null ? new ArrayList<>() : memberships;
     }
 
     @Override
@@ -80,6 +86,9 @@ public boolean isDisabled() {
         return disabled;
     }
 
+    public List<String> getMemberships() {
+        return memberships;
+    }
 
     @Override
     public int hashCode() {
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapUserManager.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapUserManager.java
index 4e2bcf816b2..c9fcaa23cc0 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapUserManager.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapUserManager.java
@@ -30,17 +30,17 @@
         MICROSOFTAD, OPENLDAP;
     }
 
-    public LdapUser getUser(final String username, final LdapContext context) throws NamingException, IOException;
+    public LdapUser getUser(final String username, final LdapContext context, Long domainId) throws NamingException, IOException;
 
-    public LdapUser getUser(final String username, final String type, final String name, final LdapContext context) throws NamingException, IOException;
+    public LdapUser getUser(final String username, final String type, final String name, final LdapContext context, Long domainId) throws NamingException, IOException;
 
-    public List<LdapUser> getUsers(final LdapContext context) throws NamingException, IOException;
+    public List<LdapUser> getUsers(final LdapContext context, Long domainId) throws NamingException, IOException;
 
-    public List<LdapUser> getUsers(final String username, final LdapContext context) throws NamingException, IOException;
+    public List<LdapUser> getUsers(final String username, final LdapContext context, Long domainId) throws NamingException, IOException;
 
-    public List<LdapUser> getUsersInGroup(String groupName, LdapContext context) throws NamingException;
+    public List<LdapUser> getUsersInGroup(String groupName, LdapContext context, Long domainId) throws NamingException;
 
-    public List<LdapUser> searchUsers(final LdapContext context) throws NamingException, IOException;
+    public List<LdapUser> searchUsers(final LdapContext context, Long domainId) throws NamingException, IOException;
 
-    public List<LdapUser> searchUsers(final String username, final LdapContext context) throws NamingException, IOException;
+    public List<LdapUser> searchUsers(final String username, final LdapContext context, Long domainId) throws NamingException, IOException;
 }
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapUtils.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapUtils.java
index d54a6991def..da0859f77ca 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapUtils.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapUtils.java
@@ -16,9 +16,12 @@
 // under the License.
 package org.apache.cloudstack.ldap;
 
+import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
 import javax.naming.directory.Attribute;
 import javax.naming.directory.Attributes;
+import java.util.ArrayList;
+import java.util.List;
 
 public final class LdapUtils {
     public static String escapeLDAPSearchFilter(final String filter) {
@@ -56,6 +59,18 @@ public static String getAttributeValue(final Attributes attributes, final String
         return null;
     }
 
+    public static List<String> getAttributeValues(final Attributes attributes, final String attributeName) throws NamingException {
+        ArrayList<String> memberships = new ArrayList<>();
+        final Attribute attribute = attributes.get(attributeName);
+        if (attribute != null) {
+            NamingEnumeration<?> values = attribute.getAll();
+            while(values.hasMore()) {
+                memberships.add(String.valueOf(values.next()));
+            }
+        }
+        return memberships;
+    }
+
     private LdapUtils() {
     }
 }
\ No newline at end of file
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/OpenLdapUserManagerImpl.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/OpenLdapUserManagerImpl.java
index 0c3e0d71705..cb3824a2ef0 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/OpenLdapUserManagerImpl.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/OpenLdapUserManagerImpl.java
@@ -50,41 +50,46 @@ public OpenLdapUserManagerImpl(final LdapConfiguration ldapConfiguration) {
         _ldapConfiguration = ldapConfiguration;
     }
 
-    protected LdapUser createUser(final SearchResult result) throws NamingException {
+    protected LdapUser createUser(final SearchResult result, Long domainId) throws NamingException {
         final Attributes attributes = result.getAttributes();
 
-        final String username = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getUsernameAttribute());
-        final String email = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getEmailAttribute());
-        final String firstname = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getFirstnameAttribute());
-        final String lastname = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getLastnameAttribute());
+        final String username = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getUsernameAttribute(domainId));
+        final String email = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getEmailAttribute(domainId));
+        final String firstname = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getFirstnameAttribute(domainId));
+        final String lastname = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getLastnameAttribute(domainId));
         final String principal = result.getNameInNamespace();
+        final List<String> memberships = LdapUtils.getAttributeValues(attributes, _ldapConfiguration.getUserMemberOfAttribute(domainId));
 
         String domain = principal.replace("cn=" + LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getCommonNameAttribute()) + ",", "");
-        domain = domain.replace("," + _ldapConfiguration.getBaseDn(), "");
+        domain = domain.replace("," + _ldapConfiguration.getBaseDn(domainId), "");
         domain = domain.replace("ou=", "");
 
         boolean disabled = isUserDisabled(result);
 
-        return new LdapUser(username, email, firstname, lastname, principal, domain, disabled);
+        return new LdapUser(username, email, firstname, lastname, principal, domain, disabled, memberships);
     }
 
-    private String generateSearchFilter(final String username) {
+    private String generateSearchFilter(final String username, Long domainId) {
         final StringBuilder userObjectFilter = new StringBuilder();
         userObjectFilter.append("(objectClass=");
-        userObjectFilter.append(_ldapConfiguration.getUserObject());
+        userObjectFilter.append(_ldapConfiguration.getUserObject(domainId));
         userObjectFilter.append(")");
 
         final StringBuilder usernameFilter = new StringBuilder();
         usernameFilter.append("(");
-        usernameFilter.append(_ldapConfiguration.getUsernameAttribute());
+        usernameFilter.append(_ldapConfiguration.getUsernameAttribute(domainId));
         usernameFilter.append("=");
         usernameFilter.append((username == null ? "*" : username));
         usernameFilter.append(")");
 
         final StringBuilder memberOfFilter = new StringBuilder();
-        if (_ldapConfiguration.getSearchGroupPrinciple() != null) {
-            memberOfFilter.append("(memberof=");
-            memberOfFilter.append(_ldapConfiguration.getSearchGroupPrinciple());
+        if (_ldapConfiguration.getSearchGroupPrinciple(domainId) != null) {
+            if(s_logger.isDebugEnabled()) {
+                s_logger.debug("adding search filter for '" + _ldapConfiguration.getSearchGroupPrinciple(domainId) +
+                "', using " + _ldapConfiguration.getUserMemberOfAttribute(domainId));
+            }
+            memberOfFilter.append("(" + _ldapConfiguration.getUserMemberOfAttribute(domainId) + "=");
+            memberOfFilter.append(_ldapConfiguration.getSearchGroupPrinciple(domainId));
             memberOfFilter.append(")");
         }
 
@@ -98,10 +103,10 @@ private String generateSearchFilter(final String username) {
         return result.toString();
     }
 
-    private String generateGroupSearchFilter(final String groupName) {
+    private String generateGroupSearchFilter(final String groupName, Long domainId) {
         final StringBuilder groupObjectFilter = new StringBuilder();
         groupObjectFilter.append("(objectClass=");
-        groupObjectFilter.append(_ldapConfiguration.getGroupObject());
+        groupObjectFilter.append(_ldapConfiguration.getGroupObject(domainId));
         groupObjectFilter.append(")");
 
         final StringBuilder groupNameFilter = new StringBuilder();
@@ -121,8 +126,8 @@ private String generateGroupSearchFilter(final String groupName) {
     }
 
     @Override
-    public LdapUser getUser(final String username, final LdapContext context) throws NamingException, IOException {
-        List<LdapUser> result = searchUsers(username, context);
+    public LdapUser getUser(final String username, final LdapContext context, Long domainId) throws NamingException, IOException {
+        List<LdapUser> result = searchUsers(username, context, domainId);
         if (result!= null && result.size() == 1) {
             return result.get(0);
         } else {
@@ -131,29 +136,29 @@ public LdapUser getUser(final String username, final LdapContext context) throws
     }
 
     @Override
-    public LdapUser getUser(final String username, final String type, final String name, final LdapContext context) throws NamingException, IOException {
+    public LdapUser getUser(final String username, final String type, final String name, final LdapContext context, Long domainId) throws NamingException, IOException {
         String basedn;
         if("OU".equals(type)) {
             basedn = name;
         } else {
-            basedn = _ldapConfiguration.getBaseDn();
+            basedn = _ldapConfiguration.getBaseDn(domainId);
         }
 
         final StringBuilder userObjectFilter = new StringBuilder();
         userObjectFilter.append("(objectClass=");
-        userObjectFilter.append(_ldapConfiguration.getUserObject());
+        userObjectFilter.append(_ldapConfiguration.getUserObject(domainId));
         userObjectFilter.append(")");
 
         final StringBuilder usernameFilter = new StringBuilder();
         usernameFilter.append("(");
-        usernameFilter.append(_ldapConfiguration.getUsernameAttribute());
+        usernameFilter.append(_ldapConfiguration.getUsernameAttribute(domainId));
         usernameFilter.append("=");
         usernameFilter.append((username == null ? "*" : username));
         usernameFilter.append(")");
 
         final StringBuilder memberOfFilter = new StringBuilder();
         if ("GROUP".equals(type)) {
-            memberOfFilter.append("(").append(getMemberOfAttribute()).append("=");
+            memberOfFilter.append("(").append(getMemberOfAttribute(domainId)).append("=");
             memberOfFilter.append(name);
             memberOfFilter.append(")");
         }
@@ -165,21 +170,21 @@ public LdapUser getUser(final String username, final String type, final String n
         searchQuery.append(memberOfFilter);
         searchQuery.append(")");
 
-        return searchUser(basedn, searchQuery.toString(), context);
+        return searchUser(basedn, searchQuery.toString(), context, domainId);
     }
 
-    protected String getMemberOfAttribute() {
-        return "memberof";
+    protected String getMemberOfAttribute(final Long domainId) {
+        return _ldapConfiguration.getUserMemberOfAttribute(domainId);
     }
 
     @Override
-    public List<LdapUser> getUsers(final LdapContext context) throws NamingException, IOException {
-        return getUsers(null, context);
+    public List<LdapUser> getUsers(final LdapContext context, Long domainId) throws NamingException, IOException {
+        return getUsers(null, context, domainId);
     }
 
     @Override
-    public List<LdapUser> getUsers(final String username, final LdapContext context) throws NamingException, IOException {
-        List<LdapUser> users = searchUsers(username, context);
+    public List<LdapUser> getUsers(final String username, final LdapContext context, Long domainId) throws NamingException, IOException {
+        List<LdapUser> users = searchUsers(username, context, domainId);
 
         if (CollectionUtils.isNotEmpty(users)) {
             Collections.sort(users);
@@ -188,13 +193,13 @@ protected String getMemberOfAttribute() {
     }
 
     @Override
-    public List<LdapUser> getUsersInGroup(String groupName, LdapContext context) throws NamingException {
-        String attributeName = _ldapConfiguration.getGroupUniqueMemeberAttribute();
+    public List<LdapUser> getUsersInGroup(String groupName, LdapContext context, Long domainId) throws NamingException {
+        String attributeName = _ldapConfiguration.getGroupUniqueMemberAttribute(domainId);
         final SearchControls controls = new SearchControls();
         controls.setSearchScope(_ldapConfiguration.getScope());
         controls.setReturningAttributes(new String[] {attributeName});
 
-        NamingEnumeration<SearchResult> result = context.search(_ldapConfiguration.getBaseDn(), generateGroupSearchFilter(groupName), controls);
+        NamingEnumeration<SearchResult> result = context.search(_ldapConfiguration.getBaseDn(domainId), generateGroupSearchFilter(groupName, domainId), controls);
 
         final List<LdapUser> users = new ArrayList<LdapUser>();
         //Expecting only one result which has all the users
@@ -205,7 +210,7 @@ protected String getMemberOfAttribute() {
             while (values.hasMoreElements()) {
                 String userdn = String.valueOf(values.nextElement());
                 try{
-                    users.add(getUserForDn(userdn, context));
+                    users.add(getUserForDn(userdn, context, domainId));
                 } catch (NamingException e){
                     s_logger.info("Userdn: " + userdn + " Not Found:: Exception message: " + e.getMessage());
                 }
@@ -217,39 +222,42 @@ protected String getMemberOfAttribute() {
         return users;
     }
 
-    private LdapUser getUserForDn(String userdn, LdapContext context) throws NamingException {
+    private LdapUser getUserForDn(String userdn, LdapContext context, Long domainId) throws NamingException {
         final SearchControls controls = new SearchControls();
         controls.setSearchScope(_ldapConfiguration.getScope());
-        controls.setReturningAttributes(_ldapConfiguration.getReturnAttributes());
+        controls.setReturningAttributes(_ldapConfiguration.getReturnAttributes(domainId));
 
-        NamingEnumeration<SearchResult> result = context.search(userdn, "(objectClass=" + _ldapConfiguration.getUserObject() + ")", controls);
+        NamingEnumeration<SearchResult> result = context.search(userdn, "(objectClass=" + _ldapConfiguration.getUserObject(domainId) + ")", controls);
         if (result.hasMoreElements()) {
-            return createUser(result.nextElement());
+            return createUser(result.nextElement(), domainId);
         } else {
             throw new NamingException("No user found for dn " + userdn);
         }
     }
 
     @Override
-    public List<LdapUser> searchUsers(final LdapContext context) throws NamingException, IOException {
-        return searchUsers(null, context);
+    public List<LdapUser> searchUsers(final LdapContext context, Long domainId) throws NamingException, IOException {
+        return searchUsers(null, context, domainId);
     }
 
     protected boolean isUserDisabled(SearchResult result) throws NamingException {
         return false;
     }
 
-    public LdapUser searchUser(final String basedn, final String searchString, final LdapContext context) throws NamingException, IOException {
+    public LdapUser searchUser(final String basedn, final String searchString, final LdapContext context, Long domainId) throws NamingException, IOException {
         final SearchControls searchControls = new SearchControls();
 
         searchControls.setSearchScope(_ldapConfiguration.getScope());
-        searchControls.setReturningAttributes(_ldapConfiguration.getReturnAttributes());
+        searchControls.setReturningAttributes(_ldapConfiguration.getReturnAttributes(domainId));
 
         NamingEnumeration<SearchResult> results = context.search(basedn, searchString, searchControls);
+        if(s_logger.isDebugEnabled()) {
+            s_logger.debug("searching user(s) with filter: \"" + searchString + "\"");
+        }
         final List<LdapUser> users = new ArrayList<LdapUser>();
         while (results.hasMoreElements()) {
             final SearchResult result = results.nextElement();
-                users.add(createUser(result));
+                users.add(createUser(result, domainId));
         }
 
         if (users.size() == 1) {
@@ -260,28 +268,28 @@ public LdapUser searchUser(final String basedn, final String searchString, final
     }
 
     @Override
-    public List<LdapUser> searchUsers(final String username, final LdapContext context) throws NamingException, IOException {
+    public List<LdapUser> searchUsers(final String username, final LdapContext context, Long domainId) throws NamingException, IOException {
 
         final SearchControls searchControls = new SearchControls();
 
         searchControls.setSearchScope(_ldapConfiguration.getScope());
-        searchControls.setReturningAttributes(_ldapConfiguration.getReturnAttributes());
+        searchControls.setReturningAttributes(_ldapConfiguration.getReturnAttributes(domainId));
 
-        String basedn = _ldapConfiguration.getBaseDn();
+        String basedn = _ldapConfiguration.getBaseDn(domainId);
         if (StringUtils.isBlank(basedn)) {
             throw new IllegalArgumentException("ldap basedn is not configured");
         }
         byte[] cookie = null;
-        int pageSize = _ldapConfiguration.getLdapPageSize();
+        int pageSize = _ldapConfiguration.getLdapPageSize(domainId);
         context.setRequestControls(new Control[]{new PagedResultsControl(pageSize, Control.NONCRITICAL)});
         final List<LdapUser> users = new ArrayList<LdapUser>();
         NamingEnumeration<SearchResult> results;
         do {
-            results = context.search(basedn, generateSearchFilter(username), searchControls);
+            results = context.search(basedn, generateSearchFilter(username, domainId), searchControls);
             while (results.hasMoreElements()) {
                 final SearchResult result = results.nextElement();
                 if (!isUserDisabled(result)) {
-                    users.add(createUser(result));
+                    users.add(createUser(result, domainId));
                 }
             }
             Control[] contextControls = context.getResponseControls();
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/dao/LdapConfigurationDao.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/dao/LdapConfigurationDao.java
index a2d5e65248e..e99c78be9b7 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/dao/LdapConfigurationDao.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/dao/LdapConfigurationDao.java
@@ -23,8 +23,19 @@
 import com.cloud.utils.Pair;
 import com.cloud.utils.db.GenericDao;
 
+/**
+ * TODO the domain value null now searches for that specifically and there is no way to search for all domains
+ */
 public interface LdapConfigurationDao extends GenericDao<LdapConfigurationVO, Long> {
+    /**
+     * @deprecated there might well be more then one ldap implementation on a host and or a double binding of several domains
+     * @param hostname
+     * @return
+     */
+    @Deprecated
     LdapConfigurationVO findByHostname(String hostname);
 
-    Pair<List<LdapConfigurationVO>, Integer> searchConfigurations(String hostname, int port);
+    LdapConfigurationVO find(String hostname, int port, Long domainId);
+
+    Pair<List<LdapConfigurationVO>, Integer> searchConfigurations(String hostname, int port, Long domainId);
 }
\ No newline at end of file
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/dao/LdapConfigurationDaoImpl.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/dao/LdapConfigurationDaoImpl.java
index 8125f8cd2de..fa4c0af236f 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/dao/LdapConfigurationDaoImpl.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/dao/LdapConfigurationDaoImpl.java
@@ -32,7 +32,8 @@
 @Component
 public class LdapConfigurationDaoImpl extends GenericDaoBase<LdapConfigurationVO, Long> implements LdapConfigurationDao {
     private final SearchBuilder<LdapConfigurationVO> hostnameSearch;
-    private final SearchBuilder<LdapConfigurationVO> listAllConfigurationsSearch;
+    private final SearchBuilder<LdapConfigurationVO> listGlobalConfigurationsSearch;
+    private final SearchBuilder<LdapConfigurationVO> listDomainConfigurationsSearch;
 
     public LdapConfigurationDaoImpl() {
         super();
@@ -40,10 +41,16 @@ public LdapConfigurationDaoImpl() {
         hostnameSearch.and("hostname", hostnameSearch.entity().getHostname(), SearchCriteria.Op.EQ);
         hostnameSearch.done();
 
-        listAllConfigurationsSearch = createSearchBuilder();
-        listAllConfigurationsSearch.and("hostname", listAllConfigurationsSearch.entity().getHostname(), Op.EQ);
-        listAllConfigurationsSearch.and("port", listAllConfigurationsSearch.entity().getPort(), Op.EQ);
-        listAllConfigurationsSearch.done();
+        listGlobalConfigurationsSearch = createSearchBuilder();
+        listGlobalConfigurationsSearch.and("hostname", listGlobalConfigurationsSearch.entity().getHostname(), Op.EQ);
+        listGlobalConfigurationsSearch.and("port", listGlobalConfigurationsSearch.entity().getPort(), Op.EQ);
+        listGlobalConfigurationsSearch.and("domain_id", listGlobalConfigurationsSearch.entity().getDomainId(),SearchCriteria.Op.NULL);
+        listGlobalConfigurationsSearch.done();
+        listDomainConfigurationsSearch = createSearchBuilder();
+        listDomainConfigurationsSearch.and("hostname", listDomainConfigurationsSearch.entity().getHostname(), Op.EQ);
+        listDomainConfigurationsSearch.and("port", listDomainConfigurationsSearch.entity().getPort(), Op.EQ);
+        listDomainConfigurationsSearch.and("domain_id", listDomainConfigurationsSearch.entity().getDomainId(), Op.EQ);
+        listDomainConfigurationsSearch.done();
     }
 
     @Override
@@ -54,11 +61,31 @@ public LdapConfigurationVO findByHostname(final String hostname) {
     }
 
     @Override
-    public Pair<List<LdapConfigurationVO>, Integer> searchConfigurations(final String hostname, final int port) {
-        final SearchCriteria<LdapConfigurationVO> sc = listAllConfigurationsSearch.create();
+    public LdapConfigurationVO find(String hostname, int port, Long domainId) {
+        SearchCriteria<LdapConfigurationVO> sc = getSearchCriteria(hostname, port, domainId);
+        return findOneBy(sc);
+    }
+
+    @Override
+    public Pair<List<LdapConfigurationVO>, Integer> searchConfigurations(final String hostname, final int port, final Long domainId) {
+        SearchCriteria<LdapConfigurationVO> sc = getSearchCriteria(hostname, port, domainId);
+        return searchAndCount(sc, null);
+    }
+
+    private SearchCriteria<LdapConfigurationVO> getSearchCriteria(String hostname, int port, Long domainId) {
+        SearchCriteria<LdapConfigurationVO> sc;
+        if (domainId == null) {
+            sc = listDomainConfigurationsSearch.create();
+        } else {
+            sc = listDomainConfigurationsSearch.create();
+            sc.setParameters("domain_id", domainId);
+        }
         if (hostname != null) {
             sc.setParameters("hostname", hostname);
         }
-        return searchAndCount(sc, null);
+        if (port > 0) {
+            sc.setParameters("port", port);
+        }
+        return sc;
     }
 }
\ No newline at end of file
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/dao/LdapTrustMapDao.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/dao/LdapTrustMapDao.java
index 7ef3799b3d8..c3d2f8aedf4 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/dao/LdapTrustMapDao.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/dao/LdapTrustMapDao.java
@@ -22,6 +22,11 @@
 
 import com.cloud.utils.db.GenericDao;
 
+import java.util.List;
+
 public interface LdapTrustMapDao extends GenericDao<LdapTrustMapVO, Long> {
     LdapTrustMapVO findByDomainId(long domainId);
+    LdapTrustMapVO findByAccount(long domainId, Long accountId);
+    LdapTrustMapVO findGroupInDomain(long domainId, String group);
+    List<LdapTrustMapVO> searchByDomainId(long domainId);
 }
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/dao/LdapTrustMapDaoImpl.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/dao/LdapTrustMapDaoImpl.java
index 57830982e70..0ecd3413d14 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/dao/LdapTrustMapDaoImpl.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/dao/LdapTrustMapDaoImpl.java
@@ -26,21 +26,55 @@
 
 import com.cloud.utils.db.GenericDaoBase;
 
+import java.util.List;
+
 @Component
 public class LdapTrustMapDaoImpl extends GenericDaoBase<LdapTrustMapVO, Long> implements LdapTrustMapDao  {
     private final SearchBuilder<LdapTrustMapVO> domainIdSearch;
+    private final SearchBuilder<LdapTrustMapVO> groupSearch;
 
     public LdapTrustMapDaoImpl() {
         super();
         domainIdSearch = createSearchBuilder();
         domainIdSearch.and("domainId", domainIdSearch.entity().getDomainId(), SearchCriteria.Op.EQ);
+        domainIdSearch.and("account_id", domainIdSearch.entity().getAccountId(),SearchCriteria.Op.EQ);
         domainIdSearch.done();
+        groupSearch = createSearchBuilder();
+        groupSearch.and("domainId", groupSearch.entity().getDomainId(), SearchCriteria.Op.EQ);
+        groupSearch.and("name", groupSearch.entity().getName(),SearchCriteria.Op.EQ);
+        groupSearch.done();
     }
 
     @Override
     public LdapTrustMapVO findByDomainId(long domainId) {
         final SearchCriteria<LdapTrustMapVO> sc = domainIdSearch.create();
         sc.setParameters("domainId", domainId);
+        sc.setParameters("account_id", 0);
+        return findOneBy(sc);
+    }
+
+    @Override
+    public LdapTrustMapVO findByAccount(long domainId, Long accountId) {
+        final SearchCriteria<LdapTrustMapVO> sc = domainIdSearch.create();
+        sc.setParameters("domainId", domainId);
+        sc.setParameters("account_id", accountId);
         return findOneBy(sc);
     }
+
+    @Override
+    public LdapTrustMapVO findGroupInDomain(long domainId, String group){
+        final SearchCriteria<LdapTrustMapVO> sc = groupSearch.create();
+        sc.setParameters("domainId", domainId);
+        sc.setParameters("name", group);
+        return findOneBy(sc);
+
+    }
+
+    @Override
+    public List<LdapTrustMapVO> searchByDomainId(long domainId) {
+        final SearchCriteria<LdapTrustMapVO> sc = domainIdSearch.create();
+        sc.setParameters("domainId", domainId);
+        return search(sc,null);
+    }
+
 }
diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/ADLdapUserManagerImplSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/ADLdapUserManagerImplSpec.groovy
index 93b1b17a460..4b631b44e3b 100644
--- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/ADLdapUserManagerImplSpec.groovy
+++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/ADLdapUserManagerImplSpec.groovy
@@ -69,13 +69,13 @@ class ADLdapUserManagerImplSpec extends spock.lang.Specification {
 
     def "test getUsersInGroup null group"() {
         ldapConfiguration.getScope() >> SearchControls.SUBTREE_SCOPE
-        ldapConfiguration.getReturnAttributes() >> ["username", "firstname", "lastname", "email"]
-        ldapConfiguration.getBaseDn() >>> [null, null, "DC=cloud,DC=citrix,DC=com"]
+        ldapConfiguration.getReturnAttributes(null) >> ["username", "firstname", "lastname", "email"]
+        ldapConfiguration.getBaseDn(null) >>> [null, null, "DC=cloud,DC=citrix,DC=com"]
 
         LdapContext context = Mock(LdapContext);
 
         when:
-            def result = adLdapUserManager.getUsersInGroup(group, context)
+            def result = adLdapUserManager.getUsersInGroup(group, context,null)
         then:
             thrown(IllegalArgumentException)
         where:
diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapAuthenticatorSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapAuthenticatorSpec.groovy
index ca19e8c633b..1ff5fce4243 100644
--- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapAuthenticatorSpec.groovy
+++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapAuthenticatorSpec.groovy
@@ -49,8 +49,8 @@ class LdapAuthenticatorSpec extends spock.lang.Specification {
         def ldapUser = Mock(LdapUser)
         ldapUser.isDisabled() >> false
         ldapManager.isLdapEnabled() >> true
-        ldapManager.getUser("rmurphy") >> ldapUser
-        ldapManager.canAuthenticate(_, _) >> false
+        ldapManager.getUser("rmurphy", null) >> ldapUser
+        ldapManager.canAuthenticate(_, _, _) >> false
 
         UserAccountDao userAccountDao = Mock(UserAccountDao)
         userAccountDao.getUserAccount(_, _) >> new UserAccountVO()
@@ -84,8 +84,8 @@ class LdapAuthenticatorSpec extends spock.lang.Specification {
         def ldapUser = Mock(LdapUser)
         ldapUser.isDisabled() >> false
         ldapManager.isLdapEnabled() >> true
-        ldapManager.canAuthenticate(_, _) >> true
-        ldapManager.getUser("rmurphy") >> ldapUser
+        ldapManager.canAuthenticate(_, _, _) >> true
+        ldapManager.getUser("rmurphy", null) >> ldapUser
 
         UserAccountDao userAccountDao = Mock(UserAccountDao)
         userAccountDao.getUserAccount(_, _) >> new UserAccountVO()
@@ -144,7 +144,7 @@ class LdapAuthenticatorSpec extends spock.lang.Specification {
         userAccountDao.getUserAccount(username, domainId) >> userAccount
         userAccount.getId() >> 1
         ldapManager.getDomainLinkedToLdap(domainId) >> new LdapTrustMapVO(domainId, type, name, (short)2)
-        ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", true)
+        ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", true, null)
         //user should be disabled in cloudstack
         accountManager.disableUser(1) >> userAccount
 
@@ -173,8 +173,8 @@ class LdapAuthenticatorSpec extends spock.lang.Specification {
         ldapManager.isLdapEnabled() >> true
         userAccountDao.getUserAccount(username, domainId) >> null
         ldapManager.getDomainLinkedToLdap(domainId) >> new LdapTrustMapVO(domainId, type, name, (short)0)
-        ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false)
-        ldapManager.canAuthenticate(_,_) >> true
+        ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false, null)
+        ldapManager.canAuthenticate(_, _, _) >> true
         //user should be created in cloudstack
         accountManager.createUserAccount(username, "", "firstname", "lastname", "email", null, username, (short) 2, domainId, username, null, _, _, User.Source.LDAP) >> Mock(UserAccount)
 
@@ -206,8 +206,8 @@ class LdapAuthenticatorSpec extends spock.lang.Specification {
         userAccount.getId() >> 1
         userAccount.getState() >> Account.State.disabled.toString()
         ldapManager.getDomainLinkedToLdap(domainId) >> new LdapTrustMapVO(domainId, type, name, (short)2)
-        ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false)
-        ldapManager.canAuthenticate(_,_) >> true
+        ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false, null)
+        ldapManager.canAuthenticate(_, _, _) >> true
         //user should be enabled in cloudstack if disabled
         accountManager.enableUser(1) >> userAccount
 
@@ -237,8 +237,8 @@ class LdapAuthenticatorSpec extends spock.lang.Specification {
         UserAccount userAccount = Mock(UserAccount)
         userAccountDao.getUserAccount(username, domainId) >> userAccount
         ldapManager.getDomainLinkedToLdap(domainId) >> new LdapTrustMapVO(domainId, type, name, (short)2)
-        ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false)
-        ldapManager.canAuthenticate(_,_) >> false
+        ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false, null)
+        ldapManager.canAuthenticate(_, _, _) >> false
 
         when:
         Pair<Boolean, UserAuthenticator.ActionOnFailedAuthentication> result = ldapAuthenticator.authenticate(username, "password", domainId, null)
diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapConfigurationDaoImplSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapConfigurationDaoImplSpec.groovy
index 144890957f2..e94b0d40fb4 100644
--- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapConfigurationDaoImplSpec.groovy
+++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapConfigurationDaoImplSpec.groovy
@@ -22,8 +22,8 @@ class LdapConfigurationDaoImplSpec extends spock.lang.Specification {
     def "Test setting up of a LdapConfigurationDao"() {
 		given: "We have an LdapConfigurationDao implementation"
         def ldapConfigurationDaoImpl = new LdapConfigurationDaoImpl();
-		expect: "that hostnameSearch and listAllConfigurationsSearch is configured"
+		expect: "that hostnameSearch and listDomainConfigurationsSearch is configured"
         ldapConfigurationDaoImpl.hostnameSearch != null;
-        ldapConfigurationDaoImpl.listAllConfigurationsSearch != null
+        ldapConfigurationDaoImpl.listDomainConfigurationsSearch != null
     }
 }
diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapConfigurationSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapConfigurationSpec.groovy
index 6f967cc6d8b..ec84d38e125 100644
--- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapConfigurationSpec.groovy
+++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapConfigurationSpec.groovy
@@ -19,55 +19,26 @@ package groovy.org.apache.cloudstack.ldap
 import org.apache.cloudstack.framework.config.ConfigKey
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import com.cloud.utils.Pair
-import org.apache.cloudstack.api.ServerApiException
 import org.apache.cloudstack.framework.config.impl.ConfigDepotImpl
 import org.apache.cloudstack.framework.config.impl.ConfigurationVO
 import org.apache.cloudstack.ldap.LdapConfiguration
 import org.apache.cloudstack.ldap.LdapConfigurationVO
-import org.apache.cloudstack.ldap.LdapManager
 import org.apache.cloudstack.ldap.LdapUserManager
 import org.apache.cloudstack.ldap.dao.LdapConfigurationDao
-import org.apache.cxf.common.util.StringUtils
 
 import javax.naming.directory.SearchControls
 
 class LdapConfigurationSpec extends spock.lang.Specification {
     def "Test that getAuthentication returns none"() {
         given: "We have a ConfigDao, LdapManager and LdapConfiguration"
-        def configDao = Mock(ConfigurationDao)
         def ldapConfigurationDao = Mock(LdapConfigurationDao)
-        def ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao)
+        def ldapConfiguration = new LdapConfiguration(ldapConfigurationDao)
         when: "Get authentication is called"
         String authentication = ldapConfiguration.getAuthentication()
         then: "none should be returned"
         authentication == "none"
     }
 
-    def "Test that getAuthentication returns simple"() {
-        given: "We have a configDao, LdapManager and LdapConfiguration with bind principle and password set"
-        def configDao = Mock(ConfigurationDao)
-        def ldapConfigurationDao = Mock(LdapConfigurationDao)
-        def ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao)
-        configDao.getValue("ldap.bind.password") >> "password"
-        configDao.getValue("ldap.bind.principal") >> "cn=rmurphy,dc=cloudstack,dc=org"
-        when: "Get authentication is called"
-        String authentication = ldapConfiguration.getAuthentication()
-        then: "authentication should be set to simple"
-        authentication == "simple"
-    }
-
-    def "Test that getBaseDn returns dc=cloudstack,dc=org"() {
-        given: "We have a ConfigDao, LdapManager and ldapConfiguration with a baseDn value set."
-        def configDao = Mock(ConfigurationDao)
-        configDao.getValue("ldap.basedn") >> "dc=cloudstack,dc=org"
-        def ldapConfigurationDao = Mock(LdapConfigurationDao)
-        def ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao)
-        when: "Get basedn is called"
-        String baseDn = ldapConfiguration.getBaseDn();
-        then: "The set baseDn should be returned"
-        baseDn == "dc=cloudstack,dc=org"
-    }
-
     def "Test that getEmailAttribute returns mail"() {
         given: "Given that we have a ConfigDao, LdapManager and LdapConfiguration"
         def configDao = Mock(ConfigurationDao)
@@ -178,87 +149,12 @@ class LdapConfigurationSpec extends spock.lang.Specification {
         LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao)
 
         when: "A request is made to get the providerUrl"
-        String providerUrl = ldapConfiguration.getProviderUrl()
+        String providerUrl = ldapConfiguration.getProviderUrl(_)
 
         then: "The providerUrl should be given."
         providerUrl == "ldap://localhost:389"
     }
 
-    def "Test that get search group principle returns successfully"() {
-        given: "We have a ConfigDao with a value for ldap.search.group.principle and an LdapConfiguration"
-        def configDao = Mock(ConfigurationDao)
-        configDao.getValue("ldap.search.group.principle") >> "cn=cloudstack,cn=users,dc=cloudstack,dc=org"
-        def ldapConfigurationDao = Mock(LdapConfigurationDao)
-        LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao)
-
-        when: "A request is made to get the search group principle"
-        String result = ldapConfiguration.getSearchGroupPrinciple();
-
-        then: "The result holds the same value configDao did"
-        result == "cn=cloudstack,cn=users,dc=cloudstack,dc=org"
-    }
-
-    def "Test that getTrustStorePassword resopnds"() {
-        given: "We have a ConfigDao with a value for truststore password"
-        def configDao = Mock(ConfigurationDao)
-        configDao.getValue("ldap.truststore.password") >> "password"
-        def ldapConfigurationDao = Mock(LdapConfigurationDao)
-        LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao)
-
-        when: "A request is made to get the truststore password"
-        String result = ldapConfiguration.getTrustStorePassword()
-
-        then: "The result is password"
-        result == "password";
-    }
-
-    def "Test that getSSLStatus can be true"() {
-        given: "We have a ConfigDao with values for truststore and truststore password set"
-        def configDao = Mock(ConfigurationDao)
-        configDao.getValue("ldap.truststore") >> "/tmp/ldap.ts"
-        configDao.getValue("ldap.truststore.password") >> "password"
-        def ldapConfigurationDao = Mock(LdapConfigurationDao)
-        LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao)
-
-        when: "A request is made to get the status of SSL"
-        boolean result = ldapConfiguration.getSSLStatus();
-
-        then: "The response should be true"
-        result == true
-    }
-
-    def "Test getgroupobject"() {
-        given: "We have configdao for ldap group object"
-        def configDao = Mock(ConfigurationDao)
-        configDao.getValue("ldap.group.object") >> groupObject
-
-        def ldapConfigurationDao = Mock(LdapConfigurationDao)
-        LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao)
-        def expectedResult = groupObject == null ? "groupOfUniqueNames" : groupObject
-
-        def result = ldapConfiguration.getGroupObject()
-        expect:
-        result == expectedResult
-        where:
-        groupObject << [null, "", "groupOfUniqueNames"]
-    }
-
-    def "Test getGroupUniqueMemeberAttribute"() {
-        given: "We have configdao for ldap group object"
-        def configDao = Mock(ConfigurationDao)
-        configDao.getValue("ldap.group.user.uniquemember") >> groupObject
-
-        def ldapConfigurationDao = Mock(LdapConfigurationDao)
-        LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao)
-        def expectedResult = groupObject == null ? "uniquemember" : groupObject
-
-        def result = ldapConfiguration.getGroupUniqueMemeberAttribute()
-        expect:
-        result == expectedResult
-        where:
-        groupObject << [null, "", "uniquemember"]
-    }
-
     def "Test getReadTimeout"() {
         given: "We have configdao for ldap group object"
         def configDao = Mock(ConfigurationDao)
@@ -275,7 +171,7 @@ class LdapConfigurationSpec extends spock.lang.Specification {
 
         def expected = timeout == null ? 1000 : timeout.toLong() //1000 is the default value
 
-        def result = ldapConfiguration.getReadTimeout()
+        def result = ldapConfiguration.getReadTimeout(null)
         expect:
         result == expected
         where:
@@ -298,7 +194,7 @@ class LdapConfigurationSpec extends spock.lang.Specification {
 
         def expected = provider.equalsIgnoreCase("microsoftad") ? LdapUserManager.Provider.MICROSOFTAD : LdapUserManager.Provider.OPENLDAP //"openldap" is the default value
 
-        def result = ldapConfiguration.getLdapProvider()
+        def result = ldapConfiguration.getLdapProvider(null)
         expect:
         println "asserting for provider configuration: " + provider
         result == expected
diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapContextFactorySpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapContextFactorySpec.groovy
index 15408833a65..eead0bcd28c 100644
--- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapContextFactorySpec.groovy
+++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapContextFactorySpec.groovy
@@ -22,7 +22,6 @@ import spock.lang.Shared
 
 import javax.naming.NamingException
 import javax.naming.directory.SearchControls
-import javax.naming.ldap.LdapContext
 
 class LdapContextFactorySpec extends spock.lang.Specification {
     @Shared
@@ -41,7 +40,7 @@ class LdapContextFactorySpec extends spock.lang.Specification {
         ldapConfiguration = Mock(LdapConfiguration)
 
         ldapConfiguration.getFactory() >> "com.sun.jndi.ldap.LdapCtxFactory"
-        ldapConfiguration.getProviderUrl() >> "ldap://localhost:389"
+        ldapConfiguration.getProviderUrl(_) >> "ldap://localhost:389"
         ldapConfiguration.getAuthentication() >> "none"
         ldapConfiguration.getScope() >> SearchControls.SUBTREE_SCOPE
         ldapConfiguration.getReturnAttributes() >> ["uid", "mail", "cn"]
@@ -49,11 +48,11 @@ class LdapContextFactorySpec extends spock.lang.Specification {
         ldapConfiguration.getEmailAttribute() >> "mail"
         ldapConfiguration.getFirstnameAttribute() >> "givenname"
         ldapConfiguration.getLastnameAttribute() >> "sn"
-        ldapConfiguration.getBaseDn() >> "dc=cloudstack,dc=org"
+        ldapConfiguration.getBaseDn(_) >> "dc=cloudstack,dc=org"
 		ldapConfiguration.getSSLStatus() >> true
 		ldapConfiguration.getTrustStore() >> "/tmp/ldap.ts"
 		ldapConfiguration.getTrustStorePassword() >> "password"
-        ldapConfiguration.getReadTimeout() >> 1000
+        ldapConfiguration.getReadTimeout(_) >> 1000
         ldapConfiguration.getLdapPageSize() >> 1
 
         username = "rmurphy"
@@ -87,7 +86,7 @@ class LdapContextFactorySpec extends spock.lang.Specification {
         def result = ldapContextFactory.getEnvironment(null, null, null, true)
 
 		then: "The resulting values should be set"
-        result['java.naming.provider.url'] == ldapConfiguration.getProviderUrl()
+        result['java.naming.provider.url'] == ldapConfiguration.getProviderUrl(null)
         result['java.naming.factory.initial'] == ldapConfiguration.getFactory()
         result['java.naming.security.principal'] == null
         result['java.naming.security.authentication'] == ldapConfiguration.getAuthentication()
@@ -102,7 +101,7 @@ class LdapContextFactorySpec extends spock.lang.Specification {
 		def result = ldapContextFactory.getEnvironment(principal, password, null, false)
 
 		then: "The resulting values should be set"
-		result['java.naming.provider.url'] == ldapConfiguration.getProviderUrl()
+		result['java.naming.provider.url'] == ldapConfiguration.getProviderUrl(null)
 		result['java.naming.factory.initial'] == ldapConfiguration.getFactory()
 		result['java.naming.security.principal'] == principal
 		result['java.naming.security.authentication'] == "simple"
diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapCreateAccountCmdSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapCreateAccountCmdSpec.groovy
index a0b20bbcb13..db4fa232b50 100644
--- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapCreateAccountCmdSpec.groovy
+++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapCreateAccountCmdSpec.groovy
@@ -16,54 +16,13 @@
 // under the License.
 package groovy.org.apache.cloudstack.ldap
 
-import com.cloud.exception.InvalidParameterValueException
-import org.apache.cloudstack.api.ServerApiException
-import org.apache.cloudstack.api.command.LdapAddConfigurationCmd
-import org.apache.cloudstack.api.response.LdapConfigurationResponse
-
 import org.apache.cloudstack.ldap.LdapUser;
 import org.apache.cloudstack.ldap.LdapManager;
 
-import org.apache.cloudstack.api.command.LdapCreateAccountCmd;
-import org.apache.cloudstack.context.CallContext;
-
-import com.cloud.user.AccountService;
-import com.cloud.user.UserAccount;
-import com.cloud.user.UserAccountVO
-import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException;
-
-import javax.naming.NamingException
+import org.apache.cloudstack.api.command.LdapCreateAccountCmd
+import com.cloud.user.AccountService
 
 class LdapCreateAccountCmdSpec extends spock.lang.Specification {
-
-    def "Test failure to retrive LDAP user"() {
-        given: "We have an LdapManager, AccountService and LdapCreateAccountCmd and LDAP user that doesn't exist"
-        LdapManager ldapManager = Mock(LdapManager)
-        ldapManager.getUser(_) >> { throw new NoLdapUserMatchingQueryException() }
-        AccountService accountService = Mock(AccountService)
-        def ldapCreateAccountCmd = Spy(LdapCreateAccountCmd, constructorArgs: [ldapManager, accountService])
-        ldapCreateAccountCmd.getCurrentContext() >> Mock(CallContext)
-        CallContext context = ldapCreateAccountCmd.getCurrentContext()
-        when: "An an account is created"
-        ldapCreateAccountCmd.execute()
-        then: "It fails and an exception is thrown"
-        thrown ServerApiException
-    }
-
-    def "Test failed creation due to a null response from cloudstack account creater"() {
-        given: "We have an LdapManager, AccountService and LdapCreateAccountCmd"
-        LdapManager ldapManager = Mock(LdapManager)
-        ldapManager.getUser(_) >> new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false)
-        AccountService accountService = Mock(AccountService)
-        def ldapCreateAccountCmd = Spy(LdapCreateAccountCmd, constructorArgs: [ldapManager, accountService])
-        ldapCreateAccountCmd.getCurrentContext() >> Mock(CallContext)
-        ldapCreateAccountCmd.createCloudstackUserAccount(_, _, _) >> null
-        when: "Cloudstack fail to create the user"
-        ldapCreateAccountCmd.execute()
-        then: "An exception is thrown"
-        thrown ServerApiException
-    }
-
     def "Test command name"() {
         given: "We have an LdapManager, AccountService and LdapCreateAccountCmd"
         LdapManager ldapManager = Mock(LdapManager)
@@ -105,7 +64,7 @@ class LdapCreateAccountCmdSpec extends spock.lang.Specification {
         AccountService accountService = Mock(AccountService)
         def ldapCreateAccountCmd = new LdapCreateAccountCmd(ldapManager, accountService);
         when: "a user with an username, email, firstname and lastname is validated"
-        def result = ldapCreateAccountCmd.validateUser(new LdapUser("username", "email", "firstname", "lastname", "principal", "domain", false))
+        def result = ldapCreateAccountCmd.validateUser(new LdapUser("username", "email", "firstname", "lastname", "principal", "domain", false, null))
         then: "the result is true"
         result == true
     }
@@ -116,7 +75,7 @@ class LdapCreateAccountCmdSpec extends spock.lang.Specification {
         AccountService accountService = Mock(AccountService)
         def ldapCreateAccountCmd = new LdapCreateAccountCmd(ldapManager, accountService)
         when: "A user with no email address attempts to validate"
-        ldapCreateAccountCmd.validateUser(new LdapUser("username", null, "firstname", "lastname", "principal", "domain", false))
+        ldapCreateAccountCmd.validateUser(new LdapUser("username", null, "firstname", "lastname", "principal", "domain", false, null))
         then: "An exception is thrown"
         thrown Exception
     }
@@ -138,7 +97,7 @@ class LdapCreateAccountCmdSpec extends spock.lang.Specification {
         AccountService accountService = Mock(AccountService)
         def ldapCreateAccountCmd = new LdapCreateAccountCmd(ldapManager, accountService)
         when: "A user with no lastname attempts to validate"
-        ldapCreateAccountCmd.validateUser(new LdapUser("username", "email", "firstname", null, "principal", "domain", false))
+        ldapCreateAccountCmd.validateUser(new LdapUser("username", "email", "firstname", null, "principal", "domain", false, null))
         then: "An exception is thown"
         thrown Exception
     }
diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapDeleteConfigurationCmdSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapDeleteConfigurationCmdSpec.groovy
index 31d56ef68cb..caa524701b2 100644
--- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapDeleteConfigurationCmdSpec.groovy
+++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapDeleteConfigurationCmdSpec.groovy
@@ -27,7 +27,7 @@ class LdapDeleteConfigurationCmdSpec extends spock.lang.Specification {
     def "Test failed response from execute"() {
 		given: "We have an LdapManager and LdapDeleteConfigurationCmd"
 		def ldapManager = Mock(LdapManager)
-        ldapManager.deleteConfiguration(_) >> { throw new InvalidParameterValueException() }
+        ldapManager.deleteConfiguration(_, 0, null) >> { throw new InvalidParameterValueException() }
         def ldapDeleteConfigurationCmd = new LdapDeleteConfigurationCmd(ldapManager)
 		when:"LdapDeleteConfigurationCmd is executed and no configuration exists"
         ldapDeleteConfigurationCmd.execute()
@@ -48,7 +48,7 @@ class LdapDeleteConfigurationCmdSpec extends spock.lang.Specification {
     def "Test successful response from execute"() {
 		given: "We have an LdapManager and LdapDeleteConfigurationCmd"
 		def ldapManager = Mock(LdapManager)
-		ldapManager.deleteConfiguration(_) >> new LdapConfigurationResponse("localhost")
+		ldapManager.deleteConfiguration(_, 0, null) >> new LdapConfigurationResponse("localhost")
 		def ldapDeleteConfigurationCmd = new LdapDeleteConfigurationCmd(ldapManager)
 		when: "LdapDeleteConfigurationCmd is executed"
 		ldapDeleteConfigurationCmd.execute()
diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy
index 434151ae234..68b910811c7 100644
--- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy
+++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy
@@ -24,10 +24,8 @@ import com.cloud.user.DomainService
 import com.cloud.user.User
 import com.cloud.user.UserAccountVO
 import com.cloud.user.UserVO
-import org.apache.cloudstack.api.command.LdapCreateAccountCmd
 import org.apache.cloudstack.api.command.LdapImportUsersCmd
 import org.apache.cloudstack.api.response.LdapUserResponse
-import org.apache.cloudstack.context.CallContext
 import org.apache.cloudstack.ldap.LdapManager
 import org.apache.cloudstack.ldap.LdapUser
 
@@ -53,9 +51,9 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification {
         def accountService = Mock(AccountService)
 
         List<LdapUser> users = new ArrayList()
-        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
-        users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
-        ldapManager.getUsers() >> users
+        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
+        users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
+        ldapManager.getUsers(null) >> users
         LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
         LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")
         ldapManager.createLdapUserResponse(_) >>> [response1, response2]
@@ -81,9 +79,9 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification {
         def accountService = Mock(AccountService)
 
         List<LdapUser> users = new ArrayList()
-        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
-        users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
-        ldapManager.getUsersInGroup("TestGroup") >> users
+        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
+        users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
+        ldapManager.getUsersInGroup("TestGroup", null) >> users
         LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
         LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")
         ldapManager.createLdapUserResponse(_) >>> [response1, response2]
@@ -110,9 +108,9 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification {
         def accountService = Mock(AccountService)
 
         List<LdapUser> users = new ArrayList()
-        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
-        users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
-        ldapManager.getUsersInGroup("TestGroup") >> users
+        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
+        users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
+        ldapManager.getUsersInGroup("TestGroup", null) >> users
         LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
         LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")
         ldapManager.createLdapUserResponse(_) >>> [response1, response2]
@@ -139,9 +137,9 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification {
         def accountService = Mock(AccountService)
 
         List<LdapUser> users = new ArrayList()
-        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
-        users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
-        ldapManager.getUsers() >> users
+        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
+        users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
+        ldapManager.getUsers(null) >> users
         LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
         LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")
         ldapManager.createLdapUserResponse(_) >>> [response1, response2]
@@ -169,8 +167,8 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification {
         ldapImportUsersCmd.domainId = varDomainId
         ldapImportUsersCmd.groupName = varGroupName
 
-        def ldapUser1 = new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false)
-        def ldapUser2 = new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false);
+        def ldapUser1 = new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null)
+        def ldapUser2 = new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null);
 
         Domain domain = new DomainVO(expectedDomainName, 1L, 1L, expectedDomainName, UUID.randomUUID().toString());
         if (varDomainId != null) {
@@ -204,8 +202,8 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification {
         given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd"
         def ldapManager = Mock(LdapManager)
         List<LdapUser> users = new ArrayList()
-        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
-        ldapManager.getUsers() >> users
+        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
+        ldapManager.getUsers(null) >> users
         LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
         ldapManager.createLdapUserResponse(_) >>> response1
 
@@ -234,8 +232,8 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification {
         given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd"
         def ldapManager = Mock(LdapManager)
         List<LdapUser> users = new ArrayList()
-        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
-        ldapManager.getUsers() >> users
+        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
+        ldapManager.getUsers(null) >> users
         LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
         ldapManager.createLdapUserResponse(_) >>> response1
 
@@ -263,8 +261,8 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification {
         given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd"
         def ldapManager = Mock(LdapManager)
         List<LdapUser> users = new ArrayList()
-        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
-        ldapManager.getUsers() >> users
+        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
+        ldapManager.getUsers(null) >> users
         LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
         ldapManager.createLdapUserResponse(_) >>> response1
 
diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapListUsersCmdSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapListUsersCmdSpec.groovy
index 5247a1ec895..d6410d96866 100644
--- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapListUsersCmdSpec.groovy
+++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapListUsersCmdSpec.groovy
@@ -40,7 +40,7 @@ class LdapListUsersCmdSpec extends spock.lang.Specification {
     def "Test successful empty response from execute"() {
 		given: "We have a LdapManager with no users, QueryService and a LdapListUsersCmd"
 	def ldapManager = Mock(LdapManager)
-	ldapManager.getUsers() >> {throw new NoLdapUserMatchingQueryException()}
+	ldapManager.getUsers(null) >> {throw new NoLdapUserMatchingQueryException()}
 		def queryService = Mock(QueryService)
 	def ldapListUsersCmd = new LdapListUsersCmd(ldapManager, queryService)
 		when: "LdapListUsersCmd is executed"
@@ -53,8 +53,8 @@ class LdapListUsersCmdSpec extends spock.lang.Specification {
 		given: "We have an LdapManager, one user, QueryService and a LdapListUsersCmd"
 		def ldapManager = Mock(LdapManager)
 		List<LdapUser> users = new ArrayList()
-		users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false))
-		ldapManager.getUsers() >> users
+		users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false, null))
+		ldapManager.getUsers(null) >> users
 		LdapUserResponse response = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null)
 		ldapManager.createLdapUserResponse(_) >> response
 		def queryService = Mock(QueryService)
@@ -92,7 +92,7 @@ class LdapListUsersCmdSpec extends spock.lang.Specification {
 
 		queryService.searchForUsers(_) >> queryServiceResponse
 
-		def ldapUser = new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false)
+		def ldapUser = new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false, null)
 		def ldapListUsersCmd = new LdapListUsersCmd(ldapManager,queryService)
 
 		when: "isACloudstackUser is executed"
@@ -109,7 +109,7 @@ class LdapListUsersCmdSpec extends spock.lang.Specification {
 
 		queryService.searchForUsers(_) >> new ListResponse<UserResponse>()
 
-		def ldapUser = new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false)
+		def ldapUser = new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false, null)
 		def ldapListUsersCmd = new LdapListUsersCmd(ldapManager,queryService)
 
 		when: "isACloudstackUser is executed"
diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapManagerImplSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapManagerImplSpec.groovy
index c9af0020848..238b2790836 100644
--- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapManagerImplSpec.groovy
+++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapManagerImplSpec.groovy
@@ -52,7 +52,7 @@ class LdapManagerImplSpec extends spock.lang.Specification {
         ldapContextFactory.createBindContext() >> { throw new NoLdapUserMatchingQueryException() }
         def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration)
         when: "We search for a user but there is a bind issue"
-        ldapManager.getUser("rmurphy")
+        ldapManager.getUser("rmurphy", null)
         then: "an exception is thrown"
         thrown NoLdapUserMatchingQueryException
     }
@@ -68,7 +68,7 @@ class LdapManagerImplSpec extends spock.lang.Specification {
         ldapContextFactory.createBindContext() >> { throw new NamingException() }
         def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration)
         when: "We search for a group of users but there is a bind issue"
-        ldapManager.getUsers()
+        ldapManager.getUsers(null)
         then: "An exception is thrown"
         thrown NoLdapUserMatchingQueryException
     }
@@ -116,7 +116,7 @@ class LdapManagerImplSpec extends spock.lang.Specification {
         def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration)
         when: "A ldap user response is generated"
         def result = ldapManager.createLdapUserResponse(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org",
-                "engineering", false))
+                "engineering", false, null))
         then: "The result of the response should match the given ldap user"
         result.username == "rmurphy"
         result.email == "rmurphy@test.com"
@@ -136,11 +136,11 @@ class LdapManagerImplSpec extends spock.lang.Specification {
         ldapUserManagerFactory.getInstance(_) >> ldapUserManager
         ldapContextFactory.createBindContext() >> null
         List<LdapUser> users = new ArrayList<>();
-        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false))
+        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false, null))
         ldapUserManager.getUsers(_) >> users;
         def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration)
         when: "We search for a group of users"
-        def result = ldapManager.getUsers()
+        def result = ldapManager.getUsers(null)
         then: "A list greater than 0 is returned"
         result.size() > 0;
     }
@@ -154,10 +154,10 @@ class LdapManagerImplSpec extends spock.lang.Specification {
         def ldapConfiguration = Mock(LdapConfiguration)
         ldapUserManagerFactory.getInstance(_) >> ldapUserManager
         ldapContextFactory.createBindContext() >> null
-        ldapUserManager.getUser(_, _) >> new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false)
+        ldapUserManager.getUser(_, _, _) >> new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false, null)
         def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration)
         when: "We search for a user"
-        def result = ldapManager.getUser("rmurphy")
+        def result = ldapManager.getUser("rmurphy", null)
         then: "The user is returned"
         result.username == "rmurphy"
         result.email == "rmurphy@test.com"
@@ -192,9 +192,9 @@ class LdapManagerImplSpec extends spock.lang.Specification {
         ldapUserManagerFactory.getInstance(_) >> ldapUserManager
         def ldapConfiguration = Mock(LdapConfiguration)
         def ldapManager = Spy(LdapManagerImpl, constructorArgs: [ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration])
-        ldapManager.getUser(_) >> { new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null) }
+        ldapManager.getUser(_, null) >> { new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null) }
         when: "The user attempts to authenticate with a bad password"
-        def result = ldapManager.canAuthenticate("rmurphy", "password")
+        def result = ldapManager.canAuthenticate("rmurphy", "password", null)
         then: "The authentication fails"
         result == false
     }
@@ -210,7 +210,7 @@ class LdapManagerImplSpec extends spock.lang.Specification {
         ldapConfigurationDao.findByHostname(_) >> null
         def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration)
         when: "A ldap configuration that doesn't exist is deleted"
-        ldapManager.deleteConfiguration("localhost")
+        ldapManager.deleteConfiguration("localhost", 0, null)
         then: "A exception is thrown"
         thrown InvalidParameterValueException
     }
@@ -242,9 +242,9 @@ class LdapManagerImplSpec extends spock.lang.Specification {
         def ldapConfiguration = Mock(LdapConfiguration)
         ldapUserManagerFactory.getInstance(_) >> ldapUserManager
         def ldapManager = Spy(LdapManagerImpl, constructorArgs: [ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration])
-        ldapManager.getUser(_) >> { new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null) }
+        ldapManager.getUser(_, null) >> { new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null) }
         when: "A user authenticates"
-        def result = ldapManager.canAuthenticate("rmurphy", "password")
+        def result = ldapManager.canAuthenticate("rmurphy", "password", null)
         then: "The result is true"
         result == true
     }
@@ -265,7 +265,7 @@ class LdapManagerImplSpec extends spock.lang.Specification {
         ldapConfigurationDao.remove(_) >> null
         def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration)
         when: "A ldap configuration is deleted"
-        def result = ldapManager.deleteConfiguration("localhost")
+        def result = ldapManager.deleteConfiguration("localhost", 0, null)
         then: "The deleted configuration is returned"
         result.hostname == "localhost"
         result.port == 389
@@ -282,7 +282,7 @@ class LdapManagerImplSpec extends spock.lang.Specification {
         ldapContextFactory.createBindContext() >> null;
 
         List<LdapUser> users = new ArrayList<LdapUser>();
-        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
+        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
         ldapUserManager.getUsers(_, _) >> users;
 
         def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration)
@@ -424,11 +424,11 @@ class LdapManagerImplSpec extends spock.lang.Specification {
         ldapUserManagerFactory.getInstance(_) >> ldapUserManager
         ldapContextFactory.createBindContext() >> null
         List<LdapUser> users = new ArrayList<>();
-        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", "engineering", false))
+        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", "engineering", false, null))
         ldapUserManager.getUsersInGroup("engineering", _) >> users;
         def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration)
         when: "We search for a group of users"
-        def result = ldapManager.getUsersInGroup("engineering")
+        def result = ldapManager.getUsersInGroup("engineering", null)
         then: "A list greater of size one is returned"
         result.size() == 1;
     }
@@ -524,7 +524,7 @@ class LdapManagerImplSpec extends spock.lang.Specification {
         def type = "GROUP"
         def name = "CN=test,DC=citrix,DC=com"
 
-        ldapUserManager.getUser(username, type, name, _) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", true)
+        ldapUserManager.getUser(username, type, name, _) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", true, null)
 
         when:
             LdapUser user = ldapManager.getUser(username, type, name)
@@ -574,7 +574,7 @@ class LdapManagerImplSpec extends spock.lang.Specification {
         def type = "GROUP"
         def name = "CN=test,DC=citrix,DC=com"
 
-        ldapUserManager.getUser(username, type, name, _) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false)
+        ldapUserManager.getUser(username, type, name, _) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false, null)
 
         when:
         LdapUser user = ldapManager.getUser(username, type, name)
diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapSearchUserCmdSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapSearchUserCmdSpec.groovy
index 55510875899..8936024c01b 100644
--- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapSearchUserCmdSpec.groovy
+++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapSearchUserCmdSpec.groovy
@@ -48,7 +48,7 @@ class LdapSearchUserCmdSpec extends spock.lang.Specification {
 	given: "We have an Ldap manager and ldap user search cmd"
         def ldapManager = Mock(LdapManager)
 		List<LdapUser> users = new ArrayList()
-		users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false))
+		users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false, null))
 		ldapManager.searchUsers(_) >> users
 		LdapUserResponse response = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null)
 		ldapManager.createLdapUserResponse(_) >> response
diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapUserSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapUserSpec.groovy
index 8ddfc9a23b8..36b37cad9d0 100644
--- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapUserSpec.groovy
+++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapUserSpec.groovy
@@ -22,7 +22,7 @@ class LdapUserSpec extends spock.lang.Specification {
 
     def "Testing LdapUsers hashCode generation"() {
 		given:
-		def userA = new LdapUser(usernameA, "", "", "", "", "", false)
+		def userA = new LdapUser(usernameA, "", "", "", "", "", false, null)
 		expect:
 		userA.hashCode() == usernameA.hashCode()
 		where:
@@ -31,8 +31,8 @@ class LdapUserSpec extends spock.lang.Specification {
 
     def "Testing that LdapUser successfully gives the correct result for a compare to"() {
 		given: "You have created two LDAP user objects"
-		def userA = new LdapUser(usernameA, "", "", "", "", "", false)
-		def userB = new LdapUser(usernameB, "", "", "", "", "", false)
+		def userA = new LdapUser(usernameA, "", "", "", "", "", false, null)
+		def userB = new LdapUser(usernameB, "", "", "", "", "", false, null)
 		expect: "That when compared the result is less than or equal to 0"
 		userA.compareTo(userB) <= 0
 		where: "The following values are used"
@@ -43,8 +43,8 @@ class LdapUserSpec extends spock.lang.Specification {
 
     def "Testing that LdapUsers equality"() {
 		given:
-		def userA = new LdapUser(usernameA, "", "", "", "", "", false)
-		def userB = new LdapUser(usernameB, "", "", "", "", "", false)
+		def userA = new LdapUser(usernameA, "", "", "", "", "", false, null)
+		def userB = new LdapUser(usernameB, "", "", "", "", "", false, null)
 		expect:
 		userA.equals(userA) == true
 		userA.equals(new Object()) == false
@@ -56,7 +56,7 @@ class LdapUserSpec extends spock.lang.Specification {
 
     def "Testing that the username is correctly set with the ldap object"() {
         given: "You have created a LDAP user object with a username"
-	def user = new LdapUser(username, "", "", "", "", "", false)
+	def user = new LdapUser(username, "", "", "", "", "", false, null)
         expect: "The username is equal to the given data source"
         user.getUsername() == username
         where: "The username is set to "
@@ -65,7 +65,7 @@ class LdapUserSpec extends spock.lang.Specification {
 
     def "Testing the email is correctly set with the ldap object"() {
         given: "You have created a LDAP user object with a email"
-	def user = new LdapUser("", email, "", "", "", "", false)
+	def user = new LdapUser("", email, "", "", "", "", false, null)
         expect: "The email is equal to the given data source"
         user.getEmail() == email
         where: "The email is set to "
@@ -74,7 +74,7 @@ class LdapUserSpec extends spock.lang.Specification {
 
     def "Testing the firstname is correctly set with the ldap object"() {
         given: "You have created a LDAP user object with a firstname"
-	def user = new LdapUser("", "", firstname, "", "", "", false)
+	def user = new LdapUser("", "", firstname, "", "", "", false, null)
         expect: "The firstname is equal to the given data source"
         user.getFirstname() == firstname
         where: "The firstname is set to "
@@ -83,7 +83,7 @@ class LdapUserSpec extends spock.lang.Specification {
 
     def "Testing the lastname is correctly set with the ldap object"() {
         given: "You have created a LDAP user object with a lastname"
-	def user = new LdapUser("", "", "", lastname, "", "", false)
+	def user = new LdapUser("", "", "", lastname, "", "", false, null)
         expect: "The lastname is equal to the given data source"
         user.getLastname() == lastname
         where: "The lastname is set to "
@@ -92,7 +92,7 @@ class LdapUserSpec extends spock.lang.Specification {
 
     def "Testing the principal is correctly set with the ldap object"() {
         given: "You have created a LDAP user object with a principal"
-	def user = new LdapUser("", "", "", "", principal, "", false)
+	def user = new LdapUser("", "", "", "", principal, "", false, null)
         expect: "The principal is equal to the given data source"
         user.getPrincipal() == principal
 	where: "The principal is set to "
@@ -101,7 +101,7 @@ class LdapUserSpec extends spock.lang.Specification {
 
     def "Testing the domain is correctly set with the ldap object"() {
 	given: "You have created a LDAP user object with a principal"
-	def user = new LdapUser("", "", "", "", "", domain, false)
+	def user = new LdapUser("", "", "", "", "", domain, false, null)
 	expect: "The principal is equal to the given data source"
 	user.getDomain() == domain
 	where: "The username is set to "
diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LinkDomainToLdapCmdSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LinkDomainToLdapCmdSpec.groovy
index bad41e82805..46b00a93d6c 100644
--- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LinkDomainToLdapCmdSpec.groovy
+++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LinkDomainToLdapCmdSpec.groovy
@@ -79,7 +79,7 @@ class LinkDomainToLdapCmdSpec extends Specification {
 
         LinkDomainToLdapResponse response = new LinkDomainToLdapResponse(domainId, type, name, (short)accountType)
         _ldapManager.linkDomainToLdap(_,_,_,_) >> response
-        _ldapManager.getUser(username, type, name) >> new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", name, "ccp", true)
+        _ldapManager.getUser(username, type, name) >> new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", name, "ccp", true, null)
 
         linkDomainToLdapCmd.admin = username
         linkDomainToLdapCmd.type = type
@@ -107,7 +107,7 @@ class LinkDomainToLdapCmdSpec extends Specification {
 
         LinkDomainToLdapResponse response = new LinkDomainToLdapResponse(domainId.toString(), type, name, (short)accountType)
         _ldapManager.linkDomainToLdap(_,_,_,_) >> response
-        _ldapManager.getUser(username, type, name) >> new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", name, "ccp", false)
+        _ldapManager.getUser(username, type, name) >> new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", name, "ccp", false, null)
 
         _accountService.getActiveAccountByName(username, domainId) >> Mock(Account)
 
@@ -204,7 +204,7 @@ class LinkDomainToLdapCmdSpec extends Specification {
 
         LinkDomainToLdapResponse response = new LinkDomainToLdapResponse(domainId.toString(), type, name, (short)accountType)
         _ldapManager.linkDomainToLdap(_,_,_,_) >> response
-        _ldapManager.getUser(username, type, name) >> new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", name, "ccp", false)
+        _ldapManager.getUser(username, type, name) >> new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", name, "ccp", false, null)
 
         _accountService.getActiveAccountByName(username, domainId) >> null
         UserAccount userAccount = Mock(UserAccount)
diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/OpenLdapUserManagerSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/OpenLdapUserManagerSpec.groovy
index cb08c8fd47c..40daa4110fc 100644
--- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/OpenLdapUserManagerSpec.groovy
+++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/OpenLdapUserManagerSpec.groovy
@@ -17,14 +17,12 @@
 package groovy.org.apache.cloudstack.ldap
 
 import org.apache.cloudstack.ldap.LdapConfiguration
-import org.apache.cloudstack.ldap.LdapUserManager
 import org.apache.cloudstack.ldap.OpenLdapUserManagerImpl
 import spock.lang.Shared
 
 import javax.naming.NamingException
 import javax.naming.directory.Attribute
 import javax.naming.directory.Attributes
-import javax.naming.directory.InitialDirContext
 import javax.naming.directory.SearchControls
 import javax.naming.directory.SearchResult
 import javax.naming.ldap.InitialLdapContext
@@ -167,12 +165,12 @@ class OpenLdapUserManagerSpec extends spock.lang.Specification {
         ldapConfiguration.getEmailAttribute() >> "mail"
         ldapConfiguration.getFirstnameAttribute() >> "givenname"
         ldapConfiguration.getLastnameAttribute() >> "sn"
-        ldapConfiguration.getBaseDn() >> "dc=cloudstack,dc=org"
+        ldapConfiguration.getBaseDn(_) >> "dc=cloudstack,dc=org"
         ldapConfiguration.getCommonNameAttribute() >> "cn"
         ldapConfiguration.getGroupObject() >> "groupOfUniqueNames"
-        ldapConfiguration.getGroupUniqueMemeberAttribute() >> "uniquemember"
+        ldapConfiguration.getGroupUniqueMemberAttribute(_) >> "uniquemember"
         ldapConfiguration.getLdapPageSize() >> 1
-        ldapConfiguration.getReadTimeout() >> 1000
+        ldapConfiguration.getReadTimeout(_) >> 1000
 
         username = "rmurphy"
         email = "rmurphy@test.com"
@@ -186,7 +184,7 @@ class OpenLdapUserManagerSpec extends spock.lang.Specification {
         def attributes = createUserAttributes(username, email, firstname, lastname)
         def search = createSearchResult(attributes)
         def userManager = new OpenLdapUserManagerImpl(ldapConfiguration)
-        def result = userManager.createUser(search)
+        def result = userManager.createUser(search,)
 
         expect: "The crated user the data supplied from LDAP"
 
@@ -290,7 +288,7 @@ class OpenLdapUserManagerSpec extends spock.lang.Specification {
         def ldapUserManager = new OpenLdapUserManagerImpl(ldapConfiguration)
 
         when: "A request for users is made"
-        def result = ldapUserManager.getUsersInGroup("engineering", createGroupSearchContextOneUser())
+        def result = ldapUserManager.getUsersInGroup("engineering", createGroupSearchContextOneUser(),)
         then: "one user is returned"
         result.size() == 1
     }
@@ -300,7 +298,7 @@ class OpenLdapUserManagerSpec extends spock.lang.Specification {
         def ldapUserManager = new OpenLdapUserManagerImpl(ldapConfiguration)
 
         when: "A request for users is made"
-        def result = ldapUserManager.getUsersInGroup("engineering", createGroupSearchContextNoUser())
+        def result = ldapUserManager.getUsersInGroup("engineering", createGroupSearchContextNoUser(),)
         then: "no user is returned"
         result.size() == 0
     }
diff --git a/plugins/user-authenticators/ldap/test/org/apache/cloudstack/api/command/LdapConfigurationChanger.java b/plugins/user-authenticators/ldap/test/org/apache/cloudstack/api/command/LdapConfigurationChanger.java
new file mode 100644
index 00000000000..61aa959e81a
--- /dev/null
+++ b/plugins/user-authenticators/ldap/test/org/apache/cloudstack/api/command/LdapConfigurationChanger.java
@@ -0,0 +1,56 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+package org.apache.cloudstack.api.command;
+
+import java.lang.reflect.Field;
+
+interface LdapConfigurationChanger {
+    /**
+     * sets a possibly not accessible field of the target object.
+     * @param target the object to set a hidden fields value in.
+     * @param name the name of the field to set.
+     * @param o intended value for the field "name"
+     * @throws IllegalAccessException
+     * @throws NoSuchFieldException
+     */
+    default void setHiddenField(Object target, final String name, final Object o) throws IllegalAccessException, NoSuchFieldException {
+        Class<?> klas = target.getClass();
+        Field f = getFirstFoundField(name, klas);
+        f.setAccessible(true);
+        f.set(target, o);
+    }
+
+    /**
+     * the first field found by this name in the class "klas" or any of it's superclasses except for {@code Object}. Implementers of this interface can decide to also return any field in implemented interfaces or in {@code Object}.
+     *
+     * @param name of the field to find
+     * @param klas class to gat a field by name "name" from
+     * @return a {@code Field} by the name "name"
+     * @throws NoSuchFieldException
+     */
+    default Field getFirstFoundField(String name, Class<?> klas) throws NoSuchFieldException {
+        try {
+            return klas.getDeclaredField(name);
+        } catch (NoSuchFieldException e) {
+            Class<?> parent = klas.getSuperclass();
+            if(parent.equals(Object.class)) {
+                throw e;
+            }
+            return getFirstFoundField(name, parent);
+        }
+    }
+}
\ No newline at end of file
diff --git a/plugins/user-authenticators/ldap/test/org/apache/cloudstack/api/command/LdapCreateAccountCmdTest.java b/plugins/user-authenticators/ldap/test/org/apache/cloudstack/api/command/LdapCreateAccountCmdTest.java
new file mode 100644
index 00000000000..a4eccbf0856
--- /dev/null
+++ b/plugins/user-authenticators/ldap/test/org/apache/cloudstack/api/command/LdapCreateAccountCmdTest.java
@@ -0,0 +1,72 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+package org.apache.cloudstack.api.command;
+
+import com.cloud.user.Account;
+import com.cloud.user.AccountService;
+import org.apache.cloudstack.acl.RoleService;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.ldap.LdapManager;
+import org.apache.cloudstack.ldap.LdapUser;
+import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.isNull;
+import static org.powermock.api.mockito.PowerMockito.spy;
+import static org.powermock.api.mockito.PowerMockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class LdapCreateAccountCmdTest implements LdapConfigurationChanger {
+    @Mock
+    LdapManager ldapManager;
+    @Mock
+    AccountService accountService;
+    @Mock
+    RoleService roleService;
+
+    LdapCreateAccountCmd ldapCreateAccountCmd;
+
+    @Before
+    public void setUp() throws NoSuchFieldException, IllegalAccessException {
+        ldapCreateAccountCmd = spy(new LdapCreateAccountCmd(ldapManager, accountService));
+        ldapCreateAccountCmd.roleService = roleService;
+        setHiddenField(ldapCreateAccountCmd,"accountType", Account.ACCOUNT_TYPE_DOMAIN_ADMIN);
+    }
+
+    @Test(expected = ServerApiException.class)
+    public void failureToRetrieveLdapUser() throws Exception {
+        // We have an LdapManager, AccountService and LdapCreateAccountCmd and LDAP user that doesn't exist
+        when(ldapManager.getUser(anyString(), isNull(Long.class))).thenThrow(NoLdapUserMatchingQueryException.class);
+        ldapCreateAccountCmd.execute();
+        fail("An exception should have been thrown: " + ServerApiException.class);
+    }
+
+    @Test(expected = ServerApiException.class)
+    public void failedCreationDueToANullResponseFromCloudstackAccountCreater() throws Exception {
+        // We have an LdapManager, AccountService and LdapCreateAccountCmd
+        LdapUser mrMurphy = new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null);
+        when(ldapManager.getUser(anyString(), isNull(Long.class))).thenReturn(mrMurphy);
+        ldapCreateAccountCmd.execute();
+        fail("An exception should have been thrown: " + ServerApiException.class);
+    }
+}
\ No newline at end of file
diff --git a/plugins/user-authenticators/ldap/test/org/apache/cloudstack/api/command/LdapImportUsersCmdTest.java b/plugins/user-authenticators/ldap/test/org/apache/cloudstack/api/command/LdapImportUsersCmdTest.java
new file mode 100644
index 00000000000..8db26733210
--- /dev/null
+++ b/plugins/user-authenticators/ldap/test/org/apache/cloudstack/api/command/LdapImportUsersCmdTest.java
@@ -0,0 +1,85 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+package org.apache.cloudstack.api.command;
+
+import com.cloud.domain.Domain;
+import com.cloud.domain.DomainVO;
+import com.cloud.user.Account;
+import com.cloud.user.AccountService;
+import com.cloud.user.DomainService;
+import org.apache.cloudstack.acl.RoleService;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.apache.cloudstack.api.response.LdapUserResponse;
+import org.apache.cloudstack.ldap.LdapManager;
+import org.apache.cloudstack.ldap.LdapUser;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import static junit.framework.TestCase.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.powermock.api.mockito.PowerMockito.spy;
+import static org.powermock.api.mockito.PowerMockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class LdapImportUsersCmdTest implements LdapConfigurationChanger {
+    @Mock
+    LdapManager ldapManager;
+    @Mock
+    AccountService accountService;
+    @Mock
+    DomainService domainService;
+    @Mock
+    RoleService roleService;
+
+    LdapImportUsersCmd ldapImportUsersCmd;
+
+    @Before
+    public void setUp() throws NoSuchFieldException, IllegalAccessException {
+        ldapImportUsersCmd = spy(new LdapImportUsersCmd(ldapManager, domainService, accountService));
+        ldapImportUsersCmd.roleService = roleService;
+        setHiddenField(ldapImportUsersCmd, "accountType", Account.ACCOUNT_TYPE_DOMAIN_ADMIN);
+    }
+
+    @Test
+    public void successfulResponseFromExecute() throws Exception {
+        List<LdapUser> users = new ArrayList();
+        users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null));
+        users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null));
+        when(ldapManager.getUsers(null)).thenReturn(users);
+        LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering");
+        LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering");
+        when(ldapManager.createLdapUserResponse(any(LdapUser.class))).thenReturn(response1).thenReturn(response2);
+
+
+        Domain domain = new DomainVO("engineering", 1L, 1L, "engineering", UUID.randomUUID().toString());
+        when(domainService.getDomainByName("engineering", 1L)).thenReturn(null, domain);
+        when(domainService.createDomain(eq("engineering"), eq(1L), eq("engineering"), anyString())).thenReturn(domain);
+
+        ldapImportUsersCmd.execute();
+        ListResponse<LdapUserResponse> resp = (ListResponse<LdapUserResponse>)ldapImportUsersCmd.getResponseObject();
+        assertEquals(" when LdapListUsersCmd is executed, a list of size 2 should be returned", 2, resp.getResponses().size());
+    }
+}
\ No newline at end of file
diff --git a/plugins/user-authenticators/ldap/test/org/apache/cloudstack/api/command/LinkAccountToLdapCmdTest.java b/plugins/user-authenticators/ldap/test/org/apache/cloudstack/api/command/LinkAccountToLdapCmdTest.java
new file mode 100644
index 00000000000..35aed6a50cf
--- /dev/null
+++ b/plugins/user-authenticators/ldap/test/org/apache/cloudstack/api/command/LinkAccountToLdapCmdTest.java
@@ -0,0 +1,97 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+
+package org.apache.cloudstack.api.command;
+
+import com.cloud.user.Account;
+import com.cloud.user.AccountService;
+import com.cloud.user.User;
+import com.cloud.user.UserAccountVO;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.response.LinkAccountToLdapResponse;
+import org.apache.cloudstack.ldap.LdapManager;
+import org.apache.cloudstack.ldap.LdapUser;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
+import static org.powermock.api.mockito.PowerMockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class LinkAccountToLdapCmdTest implements LdapConfigurationChanger {
+
+    @Mock
+    LdapManager ldapManager;
+    @Mock
+    AccountService accountService;
+
+    LinkAccountToLdapCmd linkAccountToLdapCmd;
+
+    @Before
+    public void setUp() throws NoSuchFieldException, IllegalAccessException {
+        linkAccountToLdapCmd = new LinkAccountToLdapCmd();
+        setHiddenField(linkAccountToLdapCmd, "_ldapManager", ldapManager);
+        setHiddenField(linkAccountToLdapCmd, "_accountService", accountService);
+    }
+
+    @Test
+    public void execute() throws Exception {
+        //      test with valid params and with admin who doesnt exist in cloudstack
+        long domainId = 1;
+        String type = "GROUP";
+        String ldapDomain = "CN=test,DC=ccp,DC=Citrix,DC=com";
+        short accountType = Account.ACCOUNT_TYPE_DOMAIN_ADMIN;
+        String username = "admin";
+        long accountId = 24;
+        String accountName = "test";
+
+        setHiddenField(linkAccountToLdapCmd, "ldapDomain", ldapDomain);
+        setHiddenField(linkAccountToLdapCmd, "admin", username);
+        setHiddenField(linkAccountToLdapCmd, "type", type);
+        setHiddenField(linkAccountToLdapCmd, "domainId", domainId);
+        setHiddenField(linkAccountToLdapCmd, "accountType", accountType);
+        setHiddenField(linkAccountToLdapCmd, "accountName", accountName);
+
+
+        LinkAccountToLdapResponse response = new LinkAccountToLdapResponse(String.valueOf(domainId), type, ldapDomain, (short)accountType, username, accountName);
+        when(ldapManager.linkAccountToLdap(linkAccountToLdapCmd)).thenReturn(response);
+        when(ldapManager.getUser(username, type, ldapDomain, 1L))
+                .thenReturn(new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", ldapDomain, "ccp", false, null));
+
+        when(accountService.getActiveAccountByName(username, domainId)).thenReturn(null);
+        UserAccountVO userAccount =  new UserAccountVO();
+        userAccount.setAccountId(24);
+        when(accountService.createUserAccount(eq(username), eq(""), eq("Admin"), eq("Admin"), eq("admin@ccp.citrix.com"), isNull(String.class),
+                eq(username), eq(Account.ACCOUNT_TYPE_DOMAIN_ADMIN), eq(RoleType.DomainAdmin.getId()), eq(domainId), isNull(String.class),
+                (java.util.Map<String,String>)isNull(), anyString(), anyString(), eq(User.Source.LDAP))).thenReturn(userAccount);
+
+        linkAccountToLdapCmd.execute();
+        LinkAccountToLdapResponse result = (LinkAccountToLdapResponse)linkAccountToLdapCmd.getResponseObject();
+        assertEquals("objectName", linkAccountToLdapCmd.APINAME, result.getObjectName());
+        assertEquals("commandName", linkAccountToLdapCmd.getCommandName(), result.getResponseName());
+        assertEquals("domainId", String.valueOf(domainId), result.getDomainId());
+        assertEquals("type", type, result.getType());
+        assertEquals("name", ldapDomain, result.getLdapDomain());
+        assertEquals("accountId", String.valueOf(accountId), result.getAdminId());
+    }
+}
diff --git a/plugins/user-authenticators/ldap/test/org/apache/cloudstack/api/command/LinkDomainToLdapCmdTest.java b/plugins/user-authenticators/ldap/test/org/apache/cloudstack/api/command/LinkDomainToLdapCmdTest.java
new file mode 100644
index 00000000000..8f1fa677cb9
--- /dev/null
+++ b/plugins/user-authenticators/ldap/test/org/apache/cloudstack/api/command/LinkDomainToLdapCmdTest.java
@@ -0,0 +1,98 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+package org.apache.cloudstack.api.command;
+
+import com.cloud.user.Account;
+import com.cloud.user.AccountService;
+import com.cloud.user.User;
+import com.cloud.user.UserAccountVO;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.response.LinkDomainToLdapResponse;
+import org.apache.cloudstack.ldap.LdapManager;
+import org.apache.cloudstack.ldap.LdapUser;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
+import static org.powermock.api.mockito.PowerMockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class LinkDomainToLdapCmdTest implements LdapConfigurationChanger
+{
+    @Mock
+    LdapManager ldapManager;
+    @Mock
+    AccountService accountService;
+
+    LinkDomainToLdapCmd linkDomainToLdapCmd;
+
+    @Before
+    public void setUp() throws NoSuchFieldException, IllegalAccessException {
+        linkDomainToLdapCmd = new LinkDomainToLdapCmd();
+        setHiddenField(linkDomainToLdapCmd, "_ldapManager", ldapManager);
+        setHiddenField(linkDomainToLdapCmd, "_accountService", accountService);
+    }
+
+    @After
+    public void tearDown() {
+    }
+
+    @Test
+    public void execute() throws Exception {
+//      test with valid params and with admin who doesnt exist in cloudstack
+        Long domainId = 1L;
+        String type = "GROUP";
+        String ldapDomain = "CN=test,DC=ccp,DC=Citrix,DC=com";
+        short accountType = Account.ACCOUNT_TYPE_DOMAIN_ADMIN;
+        String username = "admin";
+        long accountId = 24;
+        setHiddenField(linkDomainToLdapCmd, "ldapDomain", ldapDomain);
+        setHiddenField(linkDomainToLdapCmd, "admin", username);
+        setHiddenField(linkDomainToLdapCmd, "type", type);
+        setHiddenField(linkDomainToLdapCmd, "domainId", domainId);
+        setHiddenField(linkDomainToLdapCmd, "accountType", accountType);
+
+        LinkDomainToLdapResponse response = new LinkDomainToLdapResponse(domainId.toString(), type, ldapDomain, (short)accountType);
+        when(ldapManager.linkDomainToLdap(linkDomainToLdapCmd)).thenReturn(response);
+        when(ldapManager.getUser(username, type, ldapDomain, 1L)).thenReturn(new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", ldapDomain, "ccp", false, null));
+
+        when(accountService.getActiveAccountByName(username, domainId)).thenReturn(null);
+        UserAccountVO userAccount =  new UserAccountVO();
+        userAccount.setAccountId(24);
+        when(accountService.createUserAccount(eq(username), eq(""), eq("Admin"), eq("Admin"), eq("admin@ccp.citrix.com"), isNull(String.class),
+                eq(username), eq(Account.ACCOUNT_TYPE_DOMAIN_ADMIN), eq(RoleType.DomainAdmin.getId()), eq(domainId), isNull(String.class),
+                (java.util.Map<String,String>)isNull(), anyString(), anyString(), eq(User.Source.LDAP))).thenReturn(userAccount);
+
+
+        linkDomainToLdapCmd.execute();
+        LinkDomainToLdapResponse result = (LinkDomainToLdapResponse)linkDomainToLdapCmd.getResponseObject();
+        assertEquals("objectName", "LinkDomainToLdap", result.getObjectName());
+        assertEquals("commandName", linkDomainToLdapCmd.getCommandName(), result.getResponseName());
+        assertEquals("domainId", domainId.toString(), result.getDomainId());
+        assertEquals("type", type, result.getType());
+        assertEquals("name", ldapDomain, result.getLdapDomain());
+        assertEquals("accountId", String.valueOf(accountId), result.getAdminId());
+    }
+
+}
diff --git a/plugins/user-authenticators/ldap/test/org/apache/cloudstack/ldap/LdapConfigurationTest.java b/plugins/user-authenticators/ldap/test/org/apache/cloudstack/ldap/LdapConfigurationTest.java
new file mode 100644
index 00000000000..52c70ac0d19
--- /dev/null
+++ b/plugins/user-authenticators/ldap/test/org/apache/cloudstack/ldap/LdapConfigurationTest.java
@@ -0,0 +1,141 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+package org.apache.cloudstack.ldap;
+
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.ldap.dao.LdapConfigurationDao;
+import org.apache.cloudstack.ldap.dao.LdapConfigurationDaoImpl;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(MockitoJUnitRunner.class)
+public class LdapConfigurationTest {
+
+    LdapConfigurationDao ldapConfigurationDao;
+    LdapConfiguration ldapConfiguration;
+
+    private void overrideConfigValue(final String configKeyName, final Object o) throws IllegalAccessException, NoSuchFieldException {
+        Field configKey = LdapConfiguration.class.getDeclaredField(configKeyName);
+        configKey.setAccessible(true);
+
+        ConfigKey key = (ConfigKey)configKey.get(ldapConfiguration);
+
+        Field modifiersField = Field.class.getDeclaredField("modifiers");
+        modifiersField.setAccessible(true);
+        modifiersField.setInt(configKey, configKey.getModifiers() & ~Modifier.FINAL);
+
+        Field f = ConfigKey.class.getDeclaredField("_value");
+        f.setAccessible(true);
+        modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);
+        f.set(key, o);
+
+        Field dynamic = ConfigKey.class.getDeclaredField("_isDynamic");
+        dynamic.setAccessible(true);
+        modifiersField.setInt(dynamic, dynamic.getModifiers() & ~Modifier.FINAL);
+        dynamic.setBoolean(key, false);
+    }
+
+    @Before
+    public void init() throws Exception {
+        ldapConfigurationDao =  new LdapConfigurationDaoImpl();
+        ldapConfiguration = new LdapConfiguration(ldapConfigurationDao);;
+    }
+
+    @Test
+    public void getAuthenticationReturnsSimple() throws Exception {
+        overrideConfigValue("ldapBindPrincipal", "cn=bla");
+        overrideConfigValue("ldapBindPassword", "pw");
+        String authentication = ldapConfiguration.getAuthentication(null);
+        assertEquals("authentication should be set to simple", "simple", authentication);
+    }
+
+
+    @Test
+    public void getBaseDnReturnsABaseDn() throws Exception {
+        overrideConfigValue("ldapBaseDn", "dc=cloudstack,dc=org");
+        String baseDn = ldapConfiguration.getBaseDn(null);
+        assertEquals("The set baseDn should be returned","dc=cloudstack,dc=org", baseDn);
+    }
+
+    @Test
+    public void getGroupUniqueMemberAttribute() throws Exception {
+        String [] groupNames = {"bla", "uniquemember", "memberuid", "", null};
+        for (String groupObject: groupNames) {
+            overrideConfigValue("ldapGroupUniqueMemberAttribute", groupObject);
+            String expectedResult = null;
+            if(groupObject == null) {
+                expectedResult = "uniquemember";
+            } else {
+                expectedResult = groupObject;
+            };
+            String result = ldapConfiguration.getGroupUniqueMemberAttribute(null);
+            assertEquals("testing for " + groupObject, expectedResult, result);
+        }
+    }
+
+    @Test
+    public void getSSLStatusCanBeTrue() throws Exception {
+//        given: "We have a ConfigDao with values for truststore and truststore password set"
+        overrideConfigValue("ldapTrustStore", "/tmp/ldap.ts");
+        overrideConfigValue("ldapTrustStorePassword", "password");
+
+        assertTrue("A request is made to get the status of SSL should result in true", ldapConfiguration.getSSLStatus());
+    }
+    @Test
+    public void getSearchGroupPrincipleReturnsSuccessfully() throws Exception {
+        // We have a ConfigDao with a value for ldap.search.group.principle and an LdapConfiguration
+        overrideConfigValue("ldapSearchGroupPrinciple", "cn=cloudstack,cn=users,dc=cloudstack,dc=org");
+        String result = ldapConfiguration.getSearchGroupPrinciple(null);
+
+        assertEquals("The result holds the same value configDao did", "cn=cloudstack,cn=users,dc=cloudstack,dc=org",result);
+    }
+
+    @Test
+    public void  getTrustStorePasswordResopnds() throws Exception {
+        // We have a ConfigDao with a value for truststore password
+        overrideConfigValue("ldapTrustStorePassword", "password");
+
+        String result = ldapConfiguration.getTrustStorePassword();
+
+        assertEquals("The result is password", "password", result);
+    }
+
+
+    @Test
+    public void getGroupObject() throws Exception {
+        String [] groupNames = {"bla", "groupOfUniqueNames", "groupOfNames", "", null};
+        for (String groupObject: groupNames) {
+            overrideConfigValue("ldapGroupObject", groupObject);
+            String expectedResult = null;
+            if(groupObject == null) {
+                expectedResult = "groupOfUniqueNames";
+            } else {
+                expectedResult = groupObject;
+            };
+            String result = ldapConfiguration.getGroupObject(null);
+            assertEquals("testing for " + groupObject, expectedResult, result);
+        }
+    }
+}
\ No newline at end of file
diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java
index bc8272a1b79..d4404e15597 100644
--- a/server/src/com/cloud/configuration/Config.java
+++ b/server/src/com/cloud/configuration/Config.java
@@ -39,6 +39,10 @@
 import com.cloud.vm.UserVmManager;
 import com.cloud.vm.snapshot.VMSnapshotManager;
 
+/**
+ * @deprecated use the more dynamic ConfigKey
+ */
+@Deprecated
 public enum Config {
 
     // Alert
@@ -1814,42 +1818,6 @@
                 + "If it is set to -1, then it means always use single-part upload to upload object to S3. ",
             null),
 
-    // Ldap
-    LdapBasedn("Advanced", ManagementServer.class, String.class, "ldap.basedn", null, "Sets the basedn for LDAP", null),
-    LdapBindPassword("Advanced", ManagementServer.class, String.class, "ldap.bind.password", null, "Sets the bind password for LDAP", null),
-    LdapBindPrincipal("Advanced", ManagementServer.class, String.class, "ldap.bind.principal", null, "Sets the bind principal for LDAP", null),
-    LdapEmailAttribute("Advanced", ManagementServer.class, String.class, "ldap.email.attribute", "mail", "Sets the email attribute used within LDAP", null),
-    LdapFirstnameAttribute(
-            "Advanced",
-            ManagementServer.class,
-            String.class,
-            "ldap.firstname.attribute",
-            "givenname",
-            "Sets the firstname attribute used within LDAP",
-            null),
-    LdapLastnameAttribute("Advanced", ManagementServer.class, String.class, "ldap.lastname.attribute", "sn", "Sets the lastname attribute used within LDAP", null),
-    LdapUsernameAttribute("Advanced", ManagementServer.class, String.class, "ldap.username.attribute", "uid", "Sets the username attribute used within LDAP", null),
-    LdapUserObject("Advanced", ManagementServer.class, String.class, "ldap.user.object", "inetOrgPerson", "Sets the object type of users within LDAP", null),
-    LdapSearchGroupPrinciple(
-            "Advanced",
-            ManagementServer.class,
-            String.class,
-            "ldap.search.group.principle",
-            null,
-            "Sets the principle of the group that users must be a member of",
-            null),
-    LdapTrustStore("Advanced", ManagementServer.class, String.class, "ldap.truststore", null, "Sets the path to the truststore to use for SSL", null),
-    LdapTrustStorePassword("Advanced", ManagementServer.class, String.class, "ldap.truststore.password", null, "Sets the password for the truststore", null),
-    LdapGroupObject("Advanced", ManagementServer.class, String.class, "ldap.group.object", "groupOfUniqueNames", "Sets the object type of groups within LDAP", null),
-    LdapGroupUniqueMemberAttribute(
-            "Advanced",
-            ManagementServer.class,
-            String.class,
-            "ldap.group.user.uniquemember",
-            "uniquemember",
-            "Sets the attribute for uniquemembers within a group",
-            null),
-
     // VMSnapshots
     VMSnapshotMax("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.max", "10", "Maximum vm snapshots for a vm", null),
     VMSnapshotCreateWait("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.create.wait", "1800", "In second, timeout for create vm snapshot", null),
@@ -1979,17 +1947,6 @@ private Config(String category, Class<?> componentClass, Class<?> type, String n
         _scope = ConfigKey.Scope.Global.toString();
     }
 
-    private Config(String category, Class<?> componentClass, Class<?> type, String name, String defaultValue, String description, String range, String scope) {
-        _category = category;
-        _componentClass = componentClass;
-        _type = type;
-        _name = name;
-        _defaultValue = defaultValue;
-        _description = description;
-        _range = range;
-        _scope = scope;
-    }
-
     public String getCategory() {
         return _category;
     }
@@ -2010,10 +1967,6 @@ public String getDefaultValue() {
         return _type;
     }
 
-    public Class<?> getComponentClass() {
-        return _componentClass;
-    }
-
     public String getScope() {
         return _scope;
     }
@@ -2081,8 +2034,4 @@ public static Config getConfig(String name) {
         }
         return categories;
     }
-
-    public static List<Config> getConfigListByScope(String scope) {
-        return s_scopeLevelConfigsMap.get(scope);
-    }
 }
diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
index c3e9e11441e..9d9ac52fae5 100755
--- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -131,8 +131,10 @@
 import com.cloud.deploy.DataCenterDeployment;
 import com.cloud.deploy.DeploymentClusterPlanner;
 import com.cloud.domain.Domain;
+import com.cloud.domain.DomainDetailVO;
 import com.cloud.domain.DomainVO;
 import com.cloud.domain.dao.DomainDao;
+import com.cloud.domain.dao.DomainDetailsDao;
 import com.cloud.event.ActionEvent;
 import com.cloud.event.EventTypes;
 import com.cloud.event.UsageEventUtils;
@@ -327,6 +329,8 @@
     @Inject
     AccountDetailsDao _accountDetailsDao;
     @Inject
+    DomainDetailsDao _domainDetailsDao;
+    @Inject
     PrimaryDataStoreDao _storagePoolDao;
     @Inject
     NicSecondaryIpDao _nicSecondaryIpDao;
@@ -548,6 +552,21 @@ public String updateConfiguration(final long userId, final String name, final St
                 _imageStoreDetailsDao.addDetail(resourceId, name, value, true);
                 break;
 
+            case Domain:
+                final DomainVO domain = _domainDao.findById(resourceId);
+                if (domain == null) {
+                    throw new InvalidParameterValueException("unable to find domain by id " + resourceId);
+                }
+                DomainDetailVO domainDetailVO = _domainDetailsDao.findDetail(resourceId, name);
+                if (domainDetailVO == null) {
+                    domainDetailVO = new DomainDetailVO(resourceId, name, value);
+                    _domainDetailsDao.persist(domainDetailVO);
+                } else {
+                    domainDetailVO.setValue(value);
+                    _domainDetailsDao.update(domainDetailVO.getId(), domainDetailVO);
+                }
+                break;
+
             default:
                 throw new InvalidParameterValueException("Scope provided is invalid");
             }
@@ -655,6 +674,7 @@ public Configuration updateConfiguration(final UpdateCfgCmd cmd) throws InvalidP
         final Long storagepoolId = cmd.getStoragepoolId();
         final Long accountId = cmd.getAccountId();
         final Long imageStoreId = cmd.getImageStoreId();
+        final Long domainId = cmd.getDomainId();
         CallContext.current().setEventDetails(" Name: " + name + " New Value: " + (name.toLowerCase().contains("password") ? "*****" : value == null ? "" : value));
         // check if config value exists
         final ConfigurationVO config = _configDao.findByName(name);
@@ -700,6 +720,11 @@ public Configuration updateConfiguration(final UpdateCfgCmd cmd) throws InvalidP
             id = accountId;
             paramCountCheck++;
         }
+        if (domainId != null) {
+            scope = ConfigKey.Scope.Domain.toString();
+            id = domainId;
+            paramCountCheck++;
+        }
         if (storagepoolId != null) {
             scope = ConfigKey.Scope.StoragePool.toString();
             id = storagepoolId;
diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java
index c855c34b60f..82a37529b25 100644
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -1686,6 +1686,7 @@ private boolean hasSuitablePoolsForVolume(final VolumeVO volume, final Host host
         final Long clusterId = cmd.getClusterId();
         final Long storagepoolId = cmd.getStoragepoolId();
         final Long accountId = cmd.getAccountId();
+        final Long domainId = cmd.getDomainId();
         final Long imageStoreId = cmd.getImageStoreId();
         String scope = null;
         Long id = null;
@@ -1706,6 +1707,11 @@ private boolean hasSuitablePoolsForVolume(final VolumeVO volume, final Host host
             id = accountId;
             paramCountCheck++;
         }
+        if (domainId != null) {
+            scope = ConfigKey.Scope.Domain.toString();
+            id = domainId;
+            paramCountCheck++;
+        }
         if (storagepoolId != null) {
             scope = ConfigKey.Scope.StoragePool.toString();
             id = storagepoolId;
diff --git a/server/src/com/cloud/user/AccountManager.java b/server/src/com/cloud/user/AccountManager.java
index e0e7d3bf12d..e708b040ed9 100644
--- a/server/src/com/cloud/user/AccountManager.java
+++ b/server/src/com/cloud/user/AccountManager.java
@@ -215,4 +215,6 @@ void buildACLViewSearchCriteria(SearchCriteria<? extends ControlledViewEntity> s
             "false",
             "This parameter allows the users to enable or disable of showing secret key as a part of response for various APIs. By default it is set to false.",
             true);
+
+    boolean moveUser(long id, Long domainId, long accountId);
 }
diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java
index fea8b47a0c5..dc9fdc0a9e5 100644
--- a/server/src/com/cloud/user/AccountManagerImpl.java
+++ b/server/src/com/cloud/user/AccountManagerImpl.java
@@ -1702,17 +1702,32 @@ public boolean deleteUser(DeleteUserCmd deleteUserCmd) {
 
     @ActionEvent(eventType = EventTypes.EVENT_USER_MOVE, eventDescription = "moving User to a new account")
     public boolean moveUser(MoveUserCmd cmd) {
-        UserVO user = getValidUserVO(cmd.getId());
+        final Long id = cmd.getId();
+        UserVO user = getValidUserVO(id);
         Account oldAccount = _accountDao.findById(user.getAccountId());
         checkAccountAndAccess(user, oldAccount);
         long domainId = oldAccount.getDomainId();
 
-        long newAccountId = getNewAccountId(cmd, domainId);
+        long newAccountId = getNewAccountId(domainId, cmd.getAccountName(), cmd.getAccountId());
 
+        return moveUser(user, newAccountId);
+    }
+
+    public boolean moveUser(long id, Long domainId, long accountId) {
+        UserVO user = getValidUserVO(id);
+        Account oldAccount = _accountDao.findById(user.getAccountId());
+        checkAccountAndAccess(user, oldAccount);
+        Account newAccount = _accountDao.findById(accountId);
+        checkIfNotMovingAcrossDomains(domainId, newAccount);
+        return moveUser(user , accountId);
+    }
+
+    private boolean moveUser(UserVO user, long newAccountId) {
         if(newAccountId == user.getAccountId()) {
             // could do a not silent fail but the objective of the user is reached
             return true; // no need to create a new user object for this user
         }
+
         return Transaction.execute(new TransactionCallback<Boolean>() {
             @Override
             public Boolean doInTransaction(TransactionStatus status) {
@@ -1721,34 +1736,37 @@ public Boolean doInTransaction(TransactionStatus status) {
                 user.setUuid(UUID.randomUUID().toString());
                 _userDao.update(user.getId(),user);
                 newUser.setAccountId(newAccountId);
-                boolean success = _userDao.remove(cmd.getId());
+                boolean success = _userDao.remove(user.getId());
                 UserVO persisted = _userDao.persist(newUser);
                 return success && persisted.getUuid().equals(user.getExternalEntity());
             }
         });
     }
 
-    private long getNewAccountId(MoveUserCmd cmd, long domainId) {
+    private long getNewAccountId(long domainId, String accountName, Long accountId) {
         Account newAccount = null;
-        if (StringUtils.isNotBlank(cmd.getAccountName())) {
+        if (StringUtils.isNotBlank(accountName)) {
             if(s_logger.isDebugEnabled()) {
-                s_logger.debug("Getting id for account by name '" + cmd.getAccountName() + "' in domain " + domainId);
+                s_logger.debug("Getting id for account by name '" + accountName + "' in domain " + domainId);
             }
-            newAccount = _accountDao.findEnabledAccount(cmd.getAccountName(), domainId);
+            newAccount = _accountDao.findEnabledAccount(accountName, domainId);
         }
-        if (newAccount == null && cmd.getAccountId() != null) {
-            newAccount = _accountDao.findById(cmd.getAccountId());
+        if (newAccount == null && accountId != null) {
+            newAccount = _accountDao.findById(accountId);
         }
         if (newAccount == null) {
             throw new CloudRuntimeException("no account name or account id. this should have been caught before this point");
         }
-        long newAccountId = newAccount.getAccountId();
 
+        checkIfNotMovingAcrossDomains(domainId, newAccount);
+        return newAccount.getAccountId();
+    }
+
+    private void checkIfNotMovingAcrossDomains(long domainId, Account newAccount) {
         if(newAccount.getDomainId() != domainId) {
             // not in scope
             throw new InvalidParameterValueException("moving a user from an account in one domain to an account in annother domain is not supported!");
         }
-        return newAccountId;
     }
 
     private void checkAccountAndAccess(UserVO user, Account account) {
diff --git a/server/test/com/cloud/user/MockAccountManagerImpl.java b/server/test/com/cloud/user/MockAccountManagerImpl.java
index 8ea0473aa36..0a92c1446db 100644
--- a/server/test/com/cloud/user/MockAccountManagerImpl.java
+++ b/server/test/com/cloud/user/MockAccountManagerImpl.java
@@ -123,7 +123,13 @@ public boolean deleteUser(DeleteUserCmd deleteUserCmd) {
         return false;
     }
 
-    @Override public boolean moveUser(MoveUserCmd moveUserCmd) {
+    @Override
+    public boolean moveUser(MoveUserCmd moveUserCmd) {
+        return false;
+    }
+
+    @Override
+    public boolean moveUser(long id, Long domainId, long accountId) {
         return false;
     }
 
diff --git a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java
index 92d421c0efb..3ffec4cd020 100644
--- a/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java
+++ b/server/test/org/apache/cloudstack/networkoffering/ChildTestConfiguration.java
@@ -19,34 +19,6 @@
 
 import java.io.IOException;
 
-import com.cloud.network.dao.FirewallRulesDcidrsDaoImpl;
-import com.cloud.storage.StorageManager;
-import org.mockito.Mockito;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.ComponentScan.Filter;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.FilterType;
-import org.springframework.core.type.classreading.MetadataReader;
-import org.springframework.core.type.classreading.MetadataReaderFactory;
-import org.springframework.core.type.filter.TypeFilter;
-
-import org.apache.cloudstack.acl.SecurityChecker;
-import org.apache.cloudstack.affinity.AffinityGroupService;
-import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
-import org.apache.cloudstack.context.CallContext;
-import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
-import org.apache.cloudstack.framework.config.ConfigDepot;
-import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
-import org.apache.cloudstack.region.PortableIpDaoImpl;
-import org.apache.cloudstack.region.PortableIpRangeDaoImpl;
-import org.apache.cloudstack.region.dao.RegionDaoImpl;
-import org.apache.cloudstack.storage.datastore.db.ImageStoreDaoImpl;
-import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDaoImpl;
-import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl;
-import org.apache.cloudstack.test.utils.SpringUtils;
-
 import com.cloud.agent.AgentManager;
 import com.cloud.alert.AlertManager;
 import com.cloud.api.query.dao.UserAccountJoinDaoImpl;
@@ -67,6 +39,7 @@
 import com.cloud.dc.dao.PodVlanMapDaoImpl;
 import com.cloud.dc.dao.VlanDaoImpl;
 import com.cloud.domain.dao.DomainDaoImpl;
+import com.cloud.domain.dao.DomainDetailsDao;
 import com.cloud.event.dao.UsageEventDaoImpl;
 import com.cloud.host.dao.HostDaoImpl;
 import com.cloud.host.dao.HostDetailsDaoImpl;
@@ -79,6 +52,7 @@
 import com.cloud.network.dao.AccountGuestVlanMapDaoImpl;
 import com.cloud.network.dao.FirewallRulesCidrsDaoImpl;
 import com.cloud.network.dao.FirewallRulesDaoImpl;
+import com.cloud.network.dao.FirewallRulesDcidrsDaoImpl;
 import com.cloud.network.dao.IPAddressDaoImpl;
 import com.cloud.network.dao.LoadBalancerDaoImpl;
 import com.cloud.network.dao.NetworkDao;
@@ -107,6 +81,7 @@
 import com.cloud.server.ManagementService;
 import com.cloud.service.dao.ServiceOfferingDaoImpl;
 import com.cloud.service.dao.ServiceOfferingDetailsDaoImpl;
+import com.cloud.storage.StorageManager;
 import com.cloud.storage.dao.DiskOfferingDaoImpl;
 import com.cloud.storage.dao.SnapshotDaoImpl;
 import com.cloud.storage.dao.StoragePoolDetailsDaoImpl;
@@ -123,6 +98,30 @@
 import com.cloud.vm.dao.NicSecondaryIpDaoImpl;
 import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VMInstanceDaoImpl;
+import org.apache.cloudstack.acl.SecurityChecker;
+import org.apache.cloudstack.affinity.AffinityGroupService;
+import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
+import org.apache.cloudstack.framework.config.ConfigDepot;
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.region.PortableIpDaoImpl;
+import org.apache.cloudstack.region.PortableIpRangeDaoImpl;
+import org.apache.cloudstack.region.dao.RegionDaoImpl;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreDaoImpl;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDaoImpl;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl;
+import org.apache.cloudstack.test.utils.SpringUtils;
+import org.mockito.Mockito;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.ComponentScan.Filter;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.FilterType;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+import org.springframework.core.type.filter.TypeFilter;
 
 @Configuration
 @ComponentScan(basePackageClasses = {AccountVlanMapDaoImpl.class, DomainVlanMapDaoImpl.class, VolumeDaoImpl.class, HostPodDaoImpl.class, DomainDaoImpl.class, ServiceOfferingDaoImpl.class,
@@ -320,6 +319,11 @@ public AccountDetailsDao accountDetailsDao() {
         return Mockito.mock(AccountDetailsDao.class);
     }
 
+    @Bean
+    public DomainDetailsDao domainDetailsDao() {
+        return Mockito.mock(DomainDetailsDao.class);
+    }
+
     @Bean
     public DataStoreManager dataStoreManager() {
         return Mockito.mock(DataStoreManager.class);
diff --git a/ui/scripts/domains.js b/ui/scripts/domains.js
index 704195e08a9..1f65ff4bdae 100644
--- a/ui/scripts/domains.js
+++ b/ui/scripts/domains.js
@@ -457,6 +457,15 @@
                         }
                     }
                 },
+
+                tabFilter: function(args) {
+                    var hiddenTabs = [];
+                    if(!isAdmin()) {
+                        hiddenTabs.push('settings');
+                    }
+                    return hiddenTabs;
+                },
+
                 tabs: {
                     details: {
                         title: 'label.details',
@@ -638,36 +647,6 @@
                             domainObj["vmTotal"] = totalVMs;
                             domainObj["volumeTotal"] = totalVolumes;
 
-                            /* $.ajax({
-                url: createURL("listVirtualMachines&details=min&domainid=" + domainObj.id),
-                async: false,
-                dataType: "json",
-                success: function(json) {
-                  var items = json.listvirtualmachinesresponse.virtualmachine;
-                  var total;
-                  if (items != null)
-                    total = items.length;
-                  else
-                    total = 0;
-                  domainObj["vmTotal"] = total;
-                }
-              });
-
-              $.ajax({
-                url: createURL("listVolumes&domainid=" + domainObj.id),
-                async: false,
-                dataType: "json",
-                success: function(json) {
-                  var items = json.listvolumesresponse.volume;
-                  var total;
-                  if (items != null)
-                    total = items.length;
-                  else
-                    total = 0;
-                  domainObj["volumeTotal"] = total;
-                }
-              });*/
-
                             $.ajax({
                                 url: createURL("listResourceLimits&domainid=" + domainObj.id),
                                 async: false,
@@ -722,7 +701,58 @@
                                 actionFilter: domainActionfilter
                             });
                         }
+                    },
+                    // Granular settings for domains
+                    settings: {
+                        title: 'label.settings',
+                        custom: cloudStack.uiCustom.granularSettings({
+                            dataProvider: function(args) {
+                                $.ajax({
+                                    url: createURL('listConfigurations&domainid=' + args.context.domains[0].id),
+                                    data: listViewDataProvider(args, {}, { searchBy: 'name' }),
+                                    success: function(json) {
+                                        args.response.success({
+                                            data: json.listconfigurationsresponse.configuration
+                                        });
+
+                                    },
+
+                                    error: function(json) {
+                                        args.response.error(parseXMLHttpResponse(json));
+
+                                    }
+                                });
+
+                            },
+                            actions: {
+                                edit: function(args) {
+                                    // call updateDomainLevelParameters
+                                    var data = {
+                                        name: args.data.jsonObj.name,
+                                        value: args.data.value
+                                    };
+
+                                    $.ajax({
+                                        url: createURL('updateConfiguration&domainid=' + args.context.domains[0].id),
+                                        data: data,
+                                        success: function(json) {
+                                            var item = json.updateconfigurationresponse.configuration;
+                                            args.response.success({
+                                                data: item
+                                            });
+                                        },
+
+                                        error: function(json) {
+                                            args.response.error(parseXMLHttpResponse(json));
+                                        }
+
+                                    });
+
+                                }
+                            }
+                        })
                     }
+
                 }
             },
             labelField: 'name',


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services