You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by se...@apache.org on 2013/07/11 16:04:35 UTC

[3/3] git commit: updated refs/heads/ldapplugin to a90affe

Add LDAP Plugin Implementation


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/a90affe4
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/a90affe4
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/a90affe4

Branch: refs/heads/ldapplugin
Commit: a90affe4b34e9c2307b72f2ba6767cb93a617085
Parents: 92884d1
Author: Ian Duffy <ia...@ianduffy.ie>
Authored: Thu Jul 11 14:29:10 2013 +0100
Committer: Sebastien Goasguen <ru...@gmail.com>
Committed: Thu Jul 11 10:04:16 2013 -0400

----------------------------------------------------------------------
 .../configuration/ConfigurationService.java     |   8 -
 .../org/apache/cloudstack/api/ApiConstants.java |  11 -
 .../cloudstack/api/ResponseGenerator.java       |   3 -
 .../api/command/admin/ldap/LDAPConfigCmd.java   | 205 ------
 .../api/command/admin/ldap/LDAPRemoveCmd.java   |  71 ---
 .../api/response/LDAPConfigResponse.java        | 105 ----
 .../api/response/LDAPRemoveResponse.java        |  26 -
 client/tomcatconf/applicationContext.xml.in     |   7 +-
 client/tomcatconf/commands.properties.in        |   9 +-
 client/tomcatconf/componentContext.xml.in       |   4 +-
 client/tomcatconf/nonossComponentContext.xml.in |   4 +-
 .../tomcatconf/simulatorComponentContext.xml.in |   4 +-
 .../ratelimit/ApiRateLimitServiceImpl.java      |   1 -
 plugins/user-authenticators/ldap/pom.xml        | 149 ++++-
 .../server/auth/LDAPUserAuthenticator.java      | 173 -----
 .../api/command/LdapAddConfigurationCmd.java    |  84 +++
 .../api/command/LdapDeleteConfigurationCmd.java |  74 +++
 .../api/command/LdapListAllUsersCmd.java        |  73 +++
 .../api/command/LdapListConfigurationCmd.java   |  96 +++
 .../api/command/LdapUserSearchCmd.java          |  86 +++
 .../api/response/LdapConfigurationResponse.java |  46 ++
 .../api/response/LdapUserResponse.java          |  68 ++
 .../cloudstack/ldap/LdapAuthenticator.java      |  53 ++
 .../cloudstack/ldap/LdapConfiguration.java      | 102 +++
 .../cloudstack/ldap/LdapConfigurationVO.java    |  58 ++
 .../cloudstack/ldap/LdapContextFactory.java     |  89 +++
 .../org/apache/cloudstack/ldap/LdapManager.java |  30 +
 .../apache/cloudstack/ldap/LdapManagerImpl.java | 185 ++++++
 .../org/apache/cloudstack/ldap/LdapUser.java    |  53 ++
 .../apache/cloudstack/ldap/LdapUserManager.java |  81 +++
 .../org/apache/cloudstack/ldap/LdapUtils.java   |  46 ++
 .../ldap/NoLdapUserMatchingQueryException.java  |  16 +
 .../ldap/NoSuchLdapUserException.java           |  15 +
 .../ldap/dao/LdapConfigurationDao.java          |  14 +
 .../ldap/dao/LdapConfigurationDaoImpl.java      |  50 ++
 .../ldap/BasicNamingEnumerationImpl.groovy      |  40 ++
 .../ldap/LdapAddConfigurationCmdSpec.groovy     |  73 +++
 .../ldap/LdapAuthenticatorSpec.groovy           |  74 +++
 .../ldap/LdapConfigurationDaoImplSpec.groovy    |  13 +
 .../ldap/LdapConfigurationResponseSpec.groovy   |  33 +
 .../ldap/LdapConfigurationSpec.groovy           | 167 +++++
 .../cloudstack/ldap/LdapConfigurationVO.groovy  |  36 ++
 .../ldap/LdapContextFactorySpec.groovy          | 117 ++++
 .../ldap/LdapDeleteConfigurationCmdSpec.groovy  |  62 ++
 .../ldap/LdapListAllUsersCmdSpec.groovy         |  56 ++
 .../ldap/LdapListConfigurationCmdSpec.groovy    |  85 +++
 .../cloudstack/ldap/LdapManagerImplSpec.groovy  | 301 +++++++++
 .../ldap/LdapSearchUserCmdSpec.groovy           |  66 ++
 .../cloudstack/ldap/LdapUserManagerSpec.groovy  | 179 ++++++
 .../cloudstack/ldap/LdapUserResponseSpec.groovy |  42 ++
 .../apache/cloudstack/ldap/LdapUserSpec.groovy  |  54 ++
 .../apache/cloudstack/ldap/LdapUtilsSpec.groovy |  52 ++
 .../NoLdapUserMatchingQueryExceptionSpec.groovy |  14 +
 .../ldap/NoSuchLdapUserExceptionSpec.groovy     |  14 +
 server/src/com/cloud/api/ApiResponseHelper.java |  15 -
 server/src/com/cloud/configuration/Config.java  |  13 +-
 .../configuration/ConfigurationManagerImpl.java | 172 -----
 .../com/cloud/server/ManagementServerImpl.java  |   4 -
 .../cloud/vpc/MockConfigurationManagerImpl.java |  31 -
 setup/db/db/schema-410to420.sql                 |  15 +
 tools/apidoc/gen_toc.py                         |   2 +-
 ui/scripts/globalSettings.js                    | 625 +++++++++----------
 62 files changed, 3265 insertions(+), 1189 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/api/src/com/cloud/configuration/ConfigurationService.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/configuration/ConfigurationService.java b/api/src/com/cloud/configuration/ConfigurationService.java
index 381fcad..cc6e47f 100644
--- a/api/src/com/cloud/configuration/ConfigurationService.java
+++ b/api/src/com/cloud/configuration/ConfigurationService.java
@@ -26,8 +26,6 @@ import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.exception.ResourceAllocationException;
 import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
-import org.apache.cloudstack.api.command.admin.ldap.LDAPConfigCmd;
-import org.apache.cloudstack.api.command.admin.ldap.LDAPRemoveCmd;
 import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
 import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd;
 import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
@@ -272,12 +270,6 @@ public interface ConfigurationService {
 
     DiskOffering getDiskOffering(long diskOfferingId);
 
-    boolean updateLDAP(LDAPConfigCmd cmd) throws NamingException;
-
-	boolean removeLDAP(LDAPRemoveCmd cmd);
-
-    LDAPConfigCmd listLDAPConfig(LDAPConfigCmd cmd);
-
     /**
      * @param offering
      * @return

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/api/src/org/apache/cloudstack/api/ApiConstants.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index e2857b8..93fbff3 100755
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -527,15 +527,4 @@ public class ApiConstants {
     public enum VMDetails {
         all, group, nics, stats, secgrp, tmpl, servoff, iso, volume, min, affgrp;
     }
-
-    public enum LDAPParams {
-        hostname, port, usessl, queryfilter, searchbase, dn, passwd, truststore, truststorepass;
-
-        @Override
-        public String toString() {
-            return "ldap." + name();
-        }
-    }
-
-
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/api/src/org/apache/cloudstack/api/ResponseGenerator.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/org/apache/cloudstack/api/ResponseGenerator.java
index d8d07cb..372fc9d 100644
--- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java
+++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java
@@ -129,7 +129,6 @@ import org.apache.cloudstack.api.response.IpForwardingRuleResponse;
 import org.apache.cloudstack.api.response.IsolationMethodResponse;
 import org.apache.cloudstack.api.response.LBHealthCheckResponse;
 import org.apache.cloudstack.api.response.LBStickinessResponse;
-import org.apache.cloudstack.api.response.LDAPConfigResponse;
 import org.apache.cloudstack.api.response.LoadBalancerResponse;
 import org.apache.cloudstack.api.response.NetworkACLItemResponse;
 import org.apache.cloudstack.api.response.NetworkACLResponse;
@@ -363,8 +362,6 @@ public interface ResponseGenerator {
 
     VirtualRouterProviderResponse createVirtualRouterProviderResponse(VirtualRouterProvider result);
 
-    LDAPConfigResponse createLDAPConfigResponse(String hostname, Integer port, Boolean useSSL, String queryFilter, String baseSearch, String dn);
-
     StorageNetworkIpRangeResponse createStorageNetworkIpRangeResponse(StorageNetworkIpRange result);
 
     RegionResponse createRegionResponse(Region region);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/api/src/org/apache/cloudstack/api/command/admin/ldap/LDAPConfigCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/ldap/LDAPConfigCmd.java b/api/src/org/apache/cloudstack/api/command/admin/ldap/LDAPConfigCmd.java
deleted file mode 100644
index 38f58ec..0000000
--- a/api/src/org/apache/cloudstack/api/command/admin/ldap/LDAPConfigCmd.java
+++ /dev/null
@@ -1,205 +0,0 @@
-// 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.admin.ldap;
-
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.naming.NamingException;
-
-import org.apache.cloudstack.api.APICommand;
-import org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.api.BaseCmd;
-import org.apache.cloudstack.api.Parameter;
-import org.apache.cloudstack.api.ServerApiException;
-import org.apache.cloudstack.api.response.LDAPConfigResponse;
-import org.apache.cloudstack.api.response.ListResponse;
-import org.apache.log4j.Logger;
-
-import com.cloud.exception.ConcurrentOperationException;
-import com.cloud.exception.InsufficientCapacityException;
-import com.cloud.exception.ResourceAllocationException;
-import com.cloud.exception.ResourceUnavailableException;
-import com.cloud.exception.InvalidParameterValueException;
-import com.cloud.user.Account;
-
-@APICommand(name = "ldapConfig", description="Configure the LDAP context for this site.", responseObject=LDAPConfigResponse.class, since="3.0.0")
-public class LDAPConfigCmd extends BaseCmd  {
-    public static final Logger s_logger = Logger.getLogger(LDAPConfigCmd.class.getName());
-
-    private static final String s_name = "ldapconfigresponse";
-
-    /////////////////////////////////////////////////////
-    //////////////// API parameters /////////////////////
-    /////////////////////////////////////////////////////
-    @Parameter(name=ApiConstants.LIST_ALL, type=CommandType.BOOLEAN,  description="If true return current LDAP configuration")
-    private Boolean listAll;
-    
-    @Parameter(name=ApiConstants.HOST_NAME, type=CommandType.STRING,  description="Hostname or ip address of the ldap server eg: my.ldap.com")
-    private String hostname;
-
-    @Parameter(name=ApiConstants.PORT, type=CommandType.INTEGER, description="Specify the LDAP port if required, default is 389.")
-    private Integer port=0;
-
-    @Parameter(name=ApiConstants.USE_SSL, type=CommandType.BOOLEAN, description="Check Use SSL if the external LDAP server is configured for LDAP over SSL.")
-    private Boolean useSSL;
-
-    @Parameter(name=ApiConstants.SEARCH_BASE, type=CommandType.STRING,  description="The search base defines the starting point for the search in the directory tree Example:  dc=cloud,dc=com.")
-    private String searchBase;
-
-    @Parameter(name=ApiConstants.QUERY_FILTER, type=CommandType.STRING,  description="You specify a query filter here, which narrows down the users, who can be part of this domain.")
-    private String queryFilter;
-
-    @Parameter(name=ApiConstants.BIND_DN, type=CommandType.STRING, description="Specify the distinguished name of a user with the search permission on the directory.")
-    private String bindDN;
-
-    @Parameter(name=ApiConstants.BIND_PASSWORD, type=CommandType.STRING, description="Enter the password.")
-    private String bindPassword;
-
-    @Parameter(name=ApiConstants.TRUST_STORE, type=CommandType.STRING, description="Enter the path to trust certificates store.")
-    private String trustStore;
-
-    @Parameter(name=ApiConstants.TRUST_STORE_PASSWORD, type=CommandType.STRING, description="Enter the password for trust store.")
-    private String trustStorePassword;
-
-    /////////////////////////////////////////////////////
-    /////////////////// Accessors ///////////////////////
-    /////////////////////////////////////////////////////
-
-    public Boolean getListAll() {
-    	return listAll == null ? Boolean.FALSE : listAll;
-    }
-    
-    public String getBindPassword() {
-        return bindPassword;
-    }
-
-    public String getBindDN() {
-        return bindDN;
-    }
-
-    public void setBindDN(String bdn) {
-        this.bindDN=bdn;
-    }
-
-    public String getQueryFilter() {
-        return queryFilter;
-    }
-
-    public void setQueryFilter(String queryFilter) {
-        this.queryFilter=queryFilter;
-    }
-    public String getSearchBase() {
-        return searchBase;
-    }
-
-    public void setSearchBase(String searchBase) {
-        this.searchBase=searchBase;
-    }
-
-    public Boolean getUseSSL() {
-        return useSSL == null ? Boolean.FALSE : useSSL;
-    }
-
-    public void setUseSSL(Boolean useSSL) {
-        this.useSSL=useSSL;
-    }
-
-    public String getHostname() {
-        return hostname;
-    }
-
-    public void setHostname(String hostname) {
-        this.hostname=hostname;
-    }
-
-    public Integer getPort() {
-        return port <= 0 ? 389 : port;
-    }
-
-    public void setPort(Integer port) {
-        this.port=port;
-    }
-
-    public String getTrustStore() {
-        return trustStore;
-    }
-
-    public void setTrustStore(String trustStore) {
-        this.trustStore=trustStore;
-    }
-
-    public String getTrustStorePassword() {
-        return trustStorePassword;
-    }
-
-
-    /////////////////////////////////////////////////////
-    /////////////// API Implementation///////////////////
-    /////////////////////////////////////////////////////
-
-
-    @Override
-    public void execute() throws ResourceUnavailableException,
-            InsufficientCapacityException, ServerApiException,
-            ConcurrentOperationException, ResourceAllocationException {
-          try {
-              if (getListAll()){
-                  // return the existing conf
-                  LDAPConfigCmd cmd = _configService.listLDAPConfig(this);
-                  ListResponse<LDAPConfigResponse> response = new ListResponse<LDAPConfigResponse>();
-                  List<LDAPConfigResponse> responses = new ArrayList<LDAPConfigResponse>();
-
-                  if(!cmd.getHostname().equals("")) {
-                  	responses.add(_responseGenerator.createLDAPConfigResponse(cmd.getHostname(), cmd.getPort(), cmd.getUseSSL(), cmd.getQueryFilter(), cmd.getSearchBase(), cmd.getBindDN()));
-                  }
-                  
-                  response.setResponses(responses);
-                  response.setResponseName(getCommandName());
-                  this.setResponseObject(response);
-              }
-              else if (getHostname()==null || getSearchBase() == null || getQueryFilter() == null) {
-                  throw new InvalidParameterValueException("You need to provide hostname, searchbase and queryfilter to configure your LDAP server");
-              }
-              else {
-                  boolean result = _configService.updateLDAP(this);
-                  if (result){
-                      LDAPConfigResponse lr = _responseGenerator.createLDAPConfigResponse(getHostname(), getPort(), getUseSSL(), getQueryFilter(), getSearchBase(), getBindDN());
-                      lr.setResponseName(getCommandName());
-                      this.setResponseObject(lr);
-                  }
-              }
-          }
-          catch (NamingException ne){
-              ne.printStackTrace();
-          }
-
-    }
-
-    @Override
-    public String getCommandName() {
-        return s_name;
-    }
-
-    @Override
-    public long getEntityOwnerId() {
-        return Account.ACCOUNT_ID_SYSTEM;
-    }
-
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/api/src/org/apache/cloudstack/api/command/admin/ldap/LDAPRemoveCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/ldap/LDAPRemoveCmd.java b/api/src/org/apache/cloudstack/api/command/admin/ldap/LDAPRemoveCmd.java
deleted file mode 100644
index 5159fba..0000000
--- a/api/src/org/apache/cloudstack/api/command/admin/ldap/LDAPRemoveCmd.java
+++ /dev/null
@@ -1,71 +0,0 @@
-// 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.admin.ldap;
-
-
-import org.apache.cloudstack.api.APICommand;
-import org.apache.cloudstack.api.BaseCmd;
-import org.apache.cloudstack.api.response.LDAPConfigResponse;
-import org.apache.cloudstack.api.response.LDAPRemoveResponse;
-import org.apache.log4j.Logger;
-
-import com.cloud.user.Account;
-
-@APICommand(name = "ldapRemove", description="Remove the LDAP context for this site.", responseObject=LDAPConfigResponse.class, since="3.0.1")
-public class LDAPRemoveCmd extends BaseCmd  {
-    public static final Logger s_logger = Logger.getLogger(LDAPRemoveCmd.class.getName());
-
-    private static final String s_name = "ldapremoveresponse";
-
-    /////////////////////////////////////////////////////
-    //////////////// API parameters /////////////////////
-    /////////////////////////////////////////////////////
-
-
-    /////////////////////////////////////////////////////
-    /////////////////// Accessors ///////////////////////
-    /////////////////////////////////////////////////////
-
-
-    /////////////////////////////////////////////////////
-    /////////////// API Implementation///////////////////
-    /////////////////////////////////////////////////////
-
-
-    @Override
-    public void execute(){
-          boolean result = _configService.removeLDAP(this);
-          if (result){
-              LDAPRemoveResponse lr = new LDAPRemoveResponse();
-              lr.setObjectName("ldapremove");
-              lr.setResponseName(getCommandName());
-              this.setResponseObject(lr);
-          }
-    }
-
-    @Override
-    public String getCommandName() {
-        return s_name;
-    }
-
-    @Override
-    public long getEntityOwnerId() {
-        return Account.ACCOUNT_ID_SYSTEM;
-    }
-
-
-}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/api/src/org/apache/cloudstack/api/response/LDAPConfigResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/LDAPConfigResponse.java b/api/src/org/apache/cloudstack/api/response/LDAPConfigResponse.java
deleted file mode 100644
index bbeec63..0000000
--- a/api/src/org/apache/cloudstack/api/response/LDAPConfigResponse.java
+++ /dev/null
@@ -1,105 +0,0 @@
-// 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 org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.api.BaseResponse;
-
-import com.cloud.serializer.Param;
-import com.google.gson.annotations.SerializedName;
-
-public class LDAPConfigResponse  extends BaseResponse {
-
-    @SerializedName(ApiConstants.HOST_NAME) @Param(description="Hostname or ip address of the ldap server eg: my.ldap.com")
-    private String hostname;
-
-    @SerializedName(ApiConstants.PORT) @Param(description="Specify the LDAP port if required, default is 389")
-    private String port;
-
-    @SerializedName(ApiConstants.USE_SSL) @Param(description="Check Use SSL if the external LDAP server is configured for LDAP over SSL")
-    private String useSSL;
-
-    @SerializedName(ApiConstants.SEARCH_BASE) @Param(description="The search base defines the starting point for the search in the directory tree Example:  dc=cloud,dc=com")
-    private String searchBase;
-
-    @SerializedName(ApiConstants.QUERY_FILTER) @Param(description="You specify a query filter here, which narrows down the users, who can be part of this domain")
-    private String queryFilter;
-
-    @SerializedName(ApiConstants.BIND_DN) @Param(description="Specify the distinguished name of a user with the search permission on the directory")
-    private String bindDN;
-
-    @SerializedName(ApiConstants.BIND_PASSWORD) @Param(description="DN password")
-    private String bindPassword;
-
-    public String getHostname() {
-        return hostname;
-    }
-
-    public void setHostname(String hostname) {
-        this.hostname = hostname;
-    }
-
-    public String getPort() {
-        return port;
-    }
-
-    public void setPort(String port) {
-        this.port = port;
-    }
-
-    public String getUseSSL() {
-        return useSSL;
-    }
-
-    public void setUseSSL(String useSSL) {
-        this.useSSL = useSSL;
-    }
-
-    public String getSearchBase() {
-        return searchBase;
-    }
-
-    public void setSearchBase(String searchBase) {
-        this.searchBase = searchBase;
-    }
-
-    public String getQueryFilter() {
-        return queryFilter;
-    }
-
-    public void setQueryFilter(String queryFilter) {
-        this.queryFilter = queryFilter;
-    }
-
-    public String getBindDN() {
-        return bindDN;
-    }
-
-    public void setBindDN(String bindDN) {
-        this.bindDN = bindDN;
-    }
-
-    public String getBindPassword() {
-        return bindPassword;
-    }
-
-    public void setBindPassword(String bindPassword) {
-        this.bindPassword = bindPassword;
-    }
-
-
-}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/api/src/org/apache/cloudstack/api/response/LDAPRemoveResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/LDAPRemoveResponse.java b/api/src/org/apache/cloudstack/api/response/LDAPRemoveResponse.java
deleted file mode 100644
index 0feec5b..0000000
--- a/api/src/org/apache/cloudstack/api/response/LDAPRemoveResponse.java
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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 org.apache.cloudstack.api.BaseResponse;
-
-public class LDAPRemoveResponse extends BaseResponse {
-
-    public LDAPRemoveResponse(){
-        super();
-    }
-}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/client/tomcatconf/applicationContext.xml.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in
index 610fdfd..4b6bd34 100644
--- a/client/tomcatconf/applicationContext.xml.in
+++ b/client/tomcatconf/applicationContext.xml.in
@@ -393,7 +393,7 @@
   <bean id="MD5UserAuthenticator" class="com.cloud.server.auth.MD5UserAuthenticator">
     <property name="name" value="MD5"/>
   </bean>
-  <bean id="LDAPUserAuthenticator" class="com.cloud.server.auth.LDAPUserAuthenticator">
+  <bean id="LdapAuthenticator" class="org.apache.cloudstack.ldap.LdapAuthenticator">
     <property name="name" value="LDAP"/>
   </bean>
   <bean id="SHA256SaltedUserAuthenticator" class="com.cloud.server.auth.SHA256SaltedUserAuthenticator">
@@ -402,6 +402,11 @@
   <bean id="PlainTextUserAuthenticator" class="com.cloud.server.auth.PlainTextUserAuthenticator">
     <property name="name" value="PLAINTEXT"/>
   </bean>
+  <bean id="LdapManager" class="org.apache.cloudstack.ldap.LdapManagerImpl" />
+  <bean id="LdapUserManager" class="org.apache.cloudstack.ldap.LdapUserManager" />
+  <bean id="LdapContextFactory" class="org.apache.cloudstack.ldap.LdapContextFactory" />
+  <bean id="LdapConfigurationDao" class="org.apache.cloudstack.ldap.dao.LdapConfigurationDaoImpl" />
+  <bean id="LdapConfiguration" class="org.apache.cloudstack.ldap.LdapConfiguration" />
 
   <!--
       Network Elements

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/client/tomcatconf/commands.properties.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in
index f4b41a7..dce938f 100644
--- a/client/tomcatconf/commands.properties.in
+++ b/client/tomcatconf/commands.properties.in
@@ -210,8 +210,6 @@ scaleSystemVm=1
 #### configuration commands
 updateConfiguration=1
 listConfigurations=1
-ldapConfig=1
-ldapRemove=1
 listCapabilities=15
 listDeploymentPlanners=1
 
@@ -668,3 +666,10 @@ listDedicatedZones=1
 listDedicatedPods=1
 listDedicatedClusters=1
 listDedicatedHosts=1
+
+### LDAP
+searchLdap=1
+listLdapConfigurations=1
+addLdapConfiguration=1
+deleteLdapConfiguration=1
+listAllLdapUsers=1

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/client/tomcatconf/componentContext.xml.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in
index 1fbec61..39eab5e 100644
--- a/client/tomcatconf/componentContext.xml.in
+++ b/client/tomcatconf/componentContext.xml.in
@@ -127,7 +127,7 @@
       <list>
           <ref bean="SHA256SaltedUserAuthenticator"/>
           <ref bean="MD5UserAuthenticator"/>
-          <ref bean="LDAPUserAuthenticator"/>
+          <ref bean="LdapAuthenticator"/>
           <ref bean="PlainTextUserAuthenticator"/>
       </list>
     </property>
@@ -137,7 +137,7 @@
       <list>
           <ref bean="SHA256SaltedUserAuthenticator"/>
           <ref bean="MD5UserAuthenticator"/>
-          <ref bean="LDAPUserAuthenticator"/>
+          <ref bean="LdapAuthenticator"/>
           <ref bean="PlainTextUserAuthenticator"/>
       </list>
     </property>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/client/tomcatconf/nonossComponentContext.xml.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/nonossComponentContext.xml.in b/client/tomcatconf/nonossComponentContext.xml.in
index ffa6281..8371e37 100644
--- a/client/tomcatconf/nonossComponentContext.xml.in
+++ b/client/tomcatconf/nonossComponentContext.xml.in
@@ -223,7 +223,7 @@
       <list>
           <ref bean="SHA256SaltedUserAuthenticator"/>
           <ref bean="MD5UserAuthenticator"/>
-          <ref bean="LDAPUserAuthenticator"/>
+          <ref bean="LdapAuthenticator"/>
           <ref bean="PlainTextUserAuthenticator"/>
       </list>
     </property>
@@ -233,7 +233,7 @@
       <list>
           <ref bean="SHA256SaltedUserAuthenticator"/>
           <ref bean="MD5UserAuthenticator"/>
-          <ref bean="LDAPUserAuthenticator"/>
+          <ref bean="LdapAuthenticator"/>
           <ref bean="PlainTextUserAuthenticator"/>
       </list>
     </property>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/client/tomcatconf/simulatorComponentContext.xml.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/simulatorComponentContext.xml.in b/client/tomcatconf/simulatorComponentContext.xml.in
index 7225e84..099bdb6 100644
--- a/client/tomcatconf/simulatorComponentContext.xml.in
+++ b/client/tomcatconf/simulatorComponentContext.xml.in
@@ -73,7 +73,7 @@
       <list>
         <ref bean="SHA256SaltedUserAuthenticator"/>
         <ref bean="MD5UserAuthenticator"/>
-        <ref bean="LDAPUserAuthenticator"/>
+        <ref bean="LdapAuthenticator"/>
         <ref bean="PlainTextUserAuthenticator"/>
       </list>
     </property>
@@ -83,7 +83,7 @@
       <list>
         <ref bean="SHA256SaltedUserAuthenticator"/>
         <ref bean="MD5UserAuthenticator"/>
-        <ref bean="LDAPUserAuthenticator"/>
+        <ref bean="LdapAuthenticator"/>
         <ref bean="PlainTextUserAuthenticator"/>
       </list>
     </property>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitServiceImpl.java
----------------------------------------------------------------------
diff --git a/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitServiceImpl.java b/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitServiceImpl.java
index 7d1b43a..5566511 100644
--- a/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitServiceImpl.java
+++ b/plugins/api/rate-limit/src/org/apache/cloudstack/ratelimit/ApiRateLimitServiceImpl.java
@@ -29,7 +29,6 @@ import net.sf.ehcache.CacheManager;
 import org.apache.log4j.Logger;
 
 import org.apache.cloudstack.acl.APIChecker;
-import org.apache.cloudstack.api.ApiConstants.LDAPParams;
 import org.apache.cloudstack.api.command.admin.ratelimit.ResetApiLimitCmd;
 import org.apache.cloudstack.api.command.user.ratelimit.GetApiLimitCmd;
 import org.apache.cloudstack.api.response.ApiLimitResponse;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/plugins/user-authenticators/ldap/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/ldap/pom.xml b/plugins/user-authenticators/ldap/pom.xml
index 5c45f11..8ea67fe 100644
--- a/plugins/user-authenticators/ldap/pom.xml
+++ b/plugins/user-authenticators/ldap/pom.xml
@@ -1,29 +1,126 @@
-<!--
-  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
+<!-- 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. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<artifactId>cloud-plugin-user-authenticator-ldap</artifactId>
+	<name>Apache CloudStack Plugin - User Authenticator LDAP</name>
+	<parent>
+		<groupId>org.apache.cloudstack</groupId>
+		<artifactId>cloudstack-plugins</artifactId>
+		<version>4.2.0-SNAPSHOT</version>
+		<relativePath>../../pom.xml</relativePath>
+	</parent>
 
-  http://www.apache.org/licenses/LICENSE-2.0
+	<build>
+		<plugins>
+			<!-- Mandatory plugins for using Spock -->
+			<plugin>
+				<groupId>org.codehaus.gmaven</groupId>
+				<artifactId>gmaven-plugin</artifactId>
+				<version>1.3</version>
+				<configuration>
+					<providerSelection>1.7</providerSelection>
+				</configuration>
+				<executions>
+					<execution>
+						<goals>
+							<goal>compile</goal>
+							<goal>testCompile</goal>
+						</goals>
+						<configuration>
+							<sources>
+								<fileset>
+									<directory>test/groovy</directory>
+									<includes>
+										<include>**/*.groovy</include>
+									</includes>
+								</fileset>
+							</sources>
+						</configuration>
+					</execution>
+				</executions>
+				<dependencies>
+					<dependency>
+						<groupId>org.codehaus.gmaven.runtime</groupId>
+						<artifactId>gmaven-runtime-1.7</artifactId>
+						<version>1.3</version>
+						<exclusions>
+							<exclusion>
+								<groupId>org.codehaus.groovy</groupId>
+								<artifactId>groovy-all</artifactId>
+							</exclusion>
+						</exclusions>
+					</dependency>
+					<dependency>
+						<groupId>org.codehaus.groovy</groupId>
+						<artifactId>groovy-all</artifactId>
+						<version>2.0.5</version>
+					</dependency>
+				</dependencies>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-plugin</artifactId>
+				<configuration>
+					<includes>
+						<include>**/*Spec*</include>
+					</includes>
+				</configuration>
+			</plugin>
+		</plugins>
+		<pluginManagement>
+		  <plugins>
+		    <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
+		    <plugin>
+		      <groupId>org.eclipse.m2e</groupId>
+		      <artifactId>lifecycle-mapping</artifactId>
+		      <version>1.0.0</version>
+		      <configuration>
+		        <lifecycleMappingMetadata>
+		          <pluginExecutions>
+		            <pluginExecution>
+		              <pluginExecutionFilter>
+		                <groupId>org.codehaus.gmaven</groupId>
+		                <artifactId>gmaven-plugin</artifactId>
+		                <versionRange>[1.3,)</versionRange>
+		                <goals>
+		                  <goal>testCompile</goal>
+		                </goals>
+		              </pluginExecutionFilter>
+		              <action>
+		                <ignore></ignore>
+		              </action>
+		            </pluginExecution>
+		          </pluginExecutions>
+		        </lifecycleMappingMetadata>
+		      </configuration>
+		    </plugin>
+		  </plugins>
+		</pluginManagement>
+	</build>
 
-  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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-  <artifactId>cloud-plugin-user-authenticator-ldap</artifactId>
-  <name>Apache CloudStack Plugin - User Authenticator LDAP</name>
-  <parent>
-    <groupId>org.apache.cloudstack</groupId>
-    <artifactId>cloudstack-plugins</artifactId>
-    <version>4.2.0-SNAPSHOT</version>
-    <relativePath>../../pom.xml</relativePath>
-  </parent>
+	<dependencies>
+		<!-- Mandatory dependencies for using Spock -->
+		<dependency>
+			<groupId>org.spockframework</groupId>
+			<artifactId>spock-core</artifactId>
+			<version>0.7-groovy-2.0</version>
+		</dependency>
+
+		<!-- Optional dependencies for using Spock -->
+		<dependency> <!-- enables mocking of classes (in addition to interfaces) -->
+			<groupId>cglib</groupId>
+			<artifactId>cglib-nodep</artifactId>
+			<version>2.2</version>
+		</dependency>
+	</dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java b/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java
deleted file mode 100644
index d928a5b..0000000
--- a/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java
+++ /dev/null
@@ -1,173 +0,0 @@
-// 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.server.auth;
-
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.util.Hashtable;
-import java.util.Map;
-
-import javax.ejb.Local;
-import javax.inject.Inject;
-import javax.naming.ConfigurationException;
-import javax.naming.Context;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.InitialDirContext;
-import javax.naming.directory.SearchControls;
-import javax.naming.directory.SearchResult;
-
-import org.apache.cloudstack.api.ApiConstants.LDAPParams;
-import org.apache.log4j.Logger;
-import org.bouncycastle.util.encoders.Base64;
-
-import com.cloud.configuration.dao.ConfigurationDao;
-import com.cloud.user.UserAccount;
-import com.cloud.user.dao.UserAccountDao;
-import com.cloud.utils.exception.CloudRuntimeException;
-
-@Local(value={UserAuthenticator.class})
-public class LDAPUserAuthenticator extends DefaultUserAuthenticator {
-    public static final Logger s_logger = Logger.getLogger(LDAPUserAuthenticator.class);
-
-    @Inject private ConfigurationDao _configDao;
-    @Inject private UserAccountDao _userAccountDao;
-
-    @Override
-    public boolean authenticate(String username, String password, Long domainId, Map<String, Object[]> requestParameters ) {
-        if (s_logger.isDebugEnabled()) {
-            s_logger.debug("Retrieving user: " + username);
-        }
-        UserAccount user = _userAccountDao.getUserAccount(username, domainId);
-        if (user == null) {
-            s_logger.debug("Unable to find user with " + username + " in domain " + domainId);
-            return false;
-        }
-
-        String url = _configDao.getValue(LDAPParams.hostname.toString());
-        if (url==null){
-            s_logger.debug("LDAP authenticator is not configured.");
-            return false;
-        }
-        String port = _configDao.getValue(LDAPParams.port.toString());
-        String queryFilter = _configDao.getValue(LDAPParams.queryfilter.toString());
-        String searchBase = _configDao.getValue(LDAPParams.searchbase.toString());
-        Boolean useSSL = Boolean.valueOf(_configDao.getValue(LDAPParams.usessl.toString()));
-        String bindDN = _configDao.getValue(LDAPParams.dn.toString());
-        String bindPasswd = _configDao.getValue(LDAPParams.passwd.toString());
-        String trustStore = _configDao.getValue(LDAPParams.truststore.toString());
-        String trustStorePassword = _configDao.getValue(LDAPParams.truststorepass.toString());
-
-        try {
-            // get all params
-            Hashtable<String, String> env = new Hashtable<String, String>(11);
-            env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
-            String protocol = "ldap://" ;
-            if (useSSL){
-                env.put(Context.SECURITY_PROTOCOL, "ssl");
-                protocol="ldaps://" ;
-                System.setProperty("javax.net.ssl.trustStore", trustStore);
-                System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword);
-            }
-            env.put(Context.PROVIDER_URL, protocol + url  + ":" + port);
-
-            if (bindDN != null && bindPasswd != null){
-                env.put(Context.SECURITY_PRINCIPAL, bindDN);
-                env.put(Context.SECURITY_CREDENTIALS, bindPasswd);
-            }
-            else {
-                // Use anonymous authentication
-                env.put(Context.SECURITY_AUTHENTICATION, "none");
-            }
-            // Create the initial context
-            DirContext ctx = new InitialDirContext(env);
-            // use this context to search
-
-            // substitute the queryFilter with this user info
-            queryFilter = queryFilter.replaceAll("\\%u", username);
-            queryFilter = queryFilter.replaceAll("\\%n", user.getFirstname() + " " + user.getLastname());
-            queryFilter = queryFilter.replaceAll("\\%e", user.getEmail());
-
-
-            SearchControls sc = new SearchControls();
-            String[] searchFilter = { "dn" };
-            sc.setReturningAttributes(new String[0]); //return no attributes
-            sc.setReturningAttributes(searchFilter);
-            sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
-            sc.setCountLimit(1);
-
-            // Search for objects with those matching attributes
-            NamingEnumeration<SearchResult> answer = ctx.search(searchBase, queryFilter,  sc);
-            SearchResult sr = answer.next();
-            String cn = sr.getName();
-            answer.close();
-            ctx.close();
-
-            s_logger.info("DN from LDAP =" + cn);
-
-            // check the password
-            env = new Hashtable<String, String>(11);
-            env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
-            protocol = "ldap://" ;
-            if (useSSL){
-                env.put(Context.SECURITY_PROTOCOL, "ssl");
-                protocol="ldaps://" ;
-            }
-            env.put(Context.PROVIDER_URL, protocol + url  + ":" + port);
-            env.put(Context.SECURITY_PRINCIPAL, cn + "," + searchBase);
-            env.put(Context.SECURITY_CREDENTIALS, password);
-            // Create the initial context
-            ctx = new InitialDirContext(env);
-            ctx.close();
-
-        } catch (NamingException ne) {
-            s_logger.warn("Authentication Failed ! " + ne.getMessage() + (ne.getCause() != null ? ("; Caused by:" + ne.getCause().getMessage()) : ""));
-            return false;
-        }
-        catch (Exception e){
-            e.printStackTrace();
-            s_logger.warn("Unknown error encountered " + e.getMessage());
-            return false;
-        }
-
-        // authenticate
-        return true;
-    }
-
-    @Override
-    public boolean configure(String name, Map<String, Object> params)
-            throws ConfigurationException {
-        if (name == null) {
-            name = "LDAP";
-        }
-	super.configure(name, params);
-        return true;
-    }
-
-    @Override
-    public String encode(String password) {
-        // Password is not used, so set to a random string
-        try {
-            SecureRandom randomGen = SecureRandom.getInstance("SHA1PRNG");
-            byte bytes[] = new byte[20];
-            randomGen.nextBytes(bytes);
-            return Base64.encode(bytes).toString();
-        } catch (NoSuchAlgorithmException e) {
-            throw new CloudRuntimeException("Failed to generate random password",e);
-        }	
-    }
-}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapAddConfigurationCmd.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..62736b1
--- /dev/null
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapAddConfigurationCmd.java
@@ -0,0 +1,84 @@
+package org.apache.cloudstack.api.command;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.APICommand;
+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.LdapConfigurationResponse;
+import org.apache.cloudstack.ldap.LdapManager;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+
+@APICommand(name = "addLdapConfiguration", description = "Add a new Ldap Configuration", responseObject = LdapConfigurationResponse.class, since = "4.2.0")
+public class LdapAddConfigurationCmd extends BaseCmd {
+    public static final Logger s_logger = Logger.getLogger(LdapAddConfigurationCmd.class.getName());
+    private static final String s_name = "ldapconfigurationresponse";
+
+    @Inject
+    private LdapManager _ldapManager;
+
+    @Parameter(name = "hostname", type = CommandType.STRING, required = true, description = "Hostname")
+    private String hostname;
+
+    @Parameter(name = "port", type = CommandType.INTEGER, required = true, description = "Port")
+    private int port;
+
+    public LdapAddConfigurationCmd() {
+        super();
+    }
+
+    public LdapAddConfigurationCmd(final LdapManager ldapManager) {
+        super();
+        _ldapManager = ldapManager;
+    }
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException,
+            ConcurrentOperationException, ResourceAllocationException {
+        try {
+            final LdapConfigurationResponse response = _ldapManager.addConfiguration(getHostname(), getPort());
+            response.setObjectName("LdapAddConfiguration");
+            response.setResponseName(getCommandName());
+            setResponseObject(response);
+        } catch (final InvalidParameterValueException e) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.toString());
+        }
+
+    }
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return 0;
+    }
+
+    public String getHostname() {
+        return hostname;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setHostname(final String hostname) {
+        this.hostname = hostname;
+    }
+
+    public void setPort(final int port) {
+        this.port = port;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapDeleteConfigurationCmd.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..364b260
--- /dev/null
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapDeleteConfigurationCmd.java
@@ -0,0 +1,74 @@
+package org.apache.cloudstack.api.command;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.APICommand;
+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.LdapConfigurationResponse;
+import org.apache.cloudstack.ldap.LdapManager;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+
+@APICommand(name = "deleteLdapConfiguration", description = "Remove an Ldap Configuration", responseObject = LdapConfigurationResponse.class, since = "4.2.0")
+public class LdapDeleteConfigurationCmd extends BaseCmd {
+    public static final Logger s_logger = Logger.getLogger(LdapDeleteConfigurationCmd.class.getName());
+    private static final String s_name = "ldapconfigurationresponse";
+
+    @Inject
+    private LdapManager _ldapManager;
+
+    @Parameter(name = "hostname", type = CommandType.STRING, required = true, description = "Hostname")
+    private String hostname;
+
+    public LdapDeleteConfigurationCmd() {
+        super();
+    }
+
+    public LdapDeleteConfigurationCmd(final LdapManager ldapManager) {
+        super();
+        _ldapManager = ldapManager;
+    }
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException,
+            ConcurrentOperationException, ResourceAllocationException {
+
+        try {
+            final LdapConfigurationResponse response = _ldapManager.deleteConfiguration(getHostname());
+            response.setObjectName("LdapDeleteConfiguration");
+            response.setResponseName(getCommandName());
+            setResponseObject(response);
+        } catch (final InvalidParameterValueException e) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.toString());
+        }
+
+    }
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return 0;
+    }
+
+    public String getHostname() {
+        return hostname;
+    }
+
+    public void setHostname(final String hostname) {
+        this.hostname = hostname;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapListAllUsersCmd.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapListAllUsersCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapListAllUsersCmd.java
new file mode 100644
index 0000000..f261f74
--- /dev/null
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapListAllUsersCmd.java
@@ -0,0 +1,73 @@
+package org.apache.cloudstack.api.command;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.LdapUserResponse;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.ldap.LdapManager;
+import org.apache.cloudstack.ldap.LdapUser;
+import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+
+@APICommand(name = "listAllLdapUsers", responseObject = LdapUserResponse.class, description = "Lists all LDAP Users", since = "4.2.0")
+public class LdapListAllUsersCmd extends BaseListCmd {
+
+    public static final Logger s_logger = Logger.getLogger(LdapListAllUsersCmd.class.getName());
+    private static final String s_name = "ldapuserresponse";
+    @Inject
+    private LdapManager _ldapManager;
+
+    public LdapListAllUsersCmd() {
+        super();
+    }
+
+    public LdapListAllUsersCmd(final LdapManager ldapManager) {
+        super();
+        _ldapManager = ldapManager;
+    }
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException,
+            ConcurrentOperationException, ResourceAllocationException {
+        try {
+            final List<LdapUser> users = _ldapManager.getUsers();
+            final ListResponse<LdapUserResponse> response = new ListResponse<LdapUserResponse>();
+            final List<LdapUserResponse> ldapResponses = new ArrayList<LdapUserResponse>();
+
+            for (final LdapUser user : users) {
+                final LdapUserResponse ldapResponse = _ldapManager.createLdapUserResponse(user);
+                ldapResponse.setObjectName("LdapUser");
+                ldapResponses.add(ldapResponse);
+            }
+
+            response.setResponses(ldapResponses);
+            response.setResponseName(getCommandName());
+            setResponseObject(response);
+        } catch (final NoLdapUserMatchingQueryException ex) {
+            throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
+        }
+    }
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return 0;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapListConfigurationCmd.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..d3239e6
--- /dev/null
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapListConfigurationCmd.java
@@ -0,0 +1,96 @@
+package org.apache.cloudstack.api.command;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.LdapConfigurationResponse;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.ldap.LdapConfigurationVO;
+import org.apache.cloudstack.ldap.LdapManager;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.utils.Pair;
+
+@APICommand(name = "listLdapConfigurations", responseObject = LdapConfigurationResponse.class, description = "Lists all LDAP configurations", since = "4.2.0")
+public class LdapListConfigurationCmd extends BaseListCmd {
+    public static final Logger s_logger = Logger.getLogger(LdapListConfigurationCmd.class.getName());
+
+    private static final String s_name = "ldapconfigurationresponse";
+
+    @Inject
+    private LdapManager _ldapManager;
+
+    @Parameter(name = "hostname", type = CommandType.STRING, required = false, description = "Hostname")
+    private String hostname;
+
+    @Parameter(name = "port", type = CommandType.INTEGER, required = false, description = "Port")
+    private int port;
+
+    public LdapListConfigurationCmd() {
+        super();
+    }
+
+    public LdapListConfigurationCmd(final LdapManager ldapManager) {
+        super();
+        _ldapManager = ldapManager;
+    }
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException,
+            ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
+        final Pair<List<? extends LdapConfigurationVO>, Integer> result = _ldapManager.listConfigurations(this);
+        if (result.second() > 0) {
+            final ListResponse<LdapConfigurationResponse> response = new ListResponse<LdapConfigurationResponse>();
+            final List<LdapConfigurationResponse> responses = new ArrayList<LdapConfigurationResponse>();
+            for (final LdapConfigurationVO resource : result.first()) {
+                final LdapConfigurationResponse configurationResponse = _ldapManager.createLdapConfigurationResponse(resource);
+                configurationResponse.setObjectName("LdapConfiguration");
+                responses.add(configurationResponse);
+            }
+            response.setResponses(responses, result.second());
+            response.setResponseName(getCommandName());
+            setResponseObject(response);
+        } else {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to find any LDAP Configurations");
+        }
+    }
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return 0;
+    }
+
+    public String getHostname() {
+        return hostname;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setHostname(final String hostname) {
+        this.hostname = hostname;
+    }
+
+    public void setPort(final int port) {
+        this.port = port;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapUserSearchCmd.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapUserSearchCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapUserSearchCmd.java
new file mode 100644
index 0000000..a8d3308
--- /dev/null
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapUserSearchCmd.java
@@ -0,0 +1,86 @@
+package org.apache.cloudstack.api.command;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.LdapUserResponse;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.ldap.LdapManager;
+import org.apache.cloudstack.ldap.LdapUser;
+import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+
+@APICommand(name = "searchLdap", responseObject = LdapUserResponse.class, description = "Searches LDAP based on the username attribute", since = "4.2.0")
+public class LdapUserSearchCmd extends BaseListCmd {
+
+    public static final Logger s_logger = Logger.getLogger(LdapUserSearchCmd.class.getName());
+    private static final String s_name = "ldapuserresponse";
+    @Inject
+    private LdapManager _ldapManager;
+
+    @Parameter(name = "query", type = CommandType.STRING, entityType = LdapUserResponse.class, required = true, description = "query to search using")
+    private String query;
+
+    public LdapUserSearchCmd() {
+        super();
+    }
+
+    public LdapUserSearchCmd(final LdapManager ldapManager) {
+        super();
+        _ldapManager = ldapManager;
+    }
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException,
+            ConcurrentOperationException, ResourceAllocationException {
+        try {
+            final List<LdapUser> users = _ldapManager.searchUsers(getQuery());
+
+            final ListResponse<LdapUserResponse> response = new ListResponse<LdapUserResponse>();
+            final List<LdapUserResponse> ldapUserResponses = new ArrayList<LdapUserResponse>();
+
+            for (final LdapUser user : users) {
+                final LdapUserResponse ldapUserResponse = _ldapManager.createLdapUserResponse(user);
+                ldapUserResponse.setObjectName("LdapUser");
+                ldapUserResponses.add(ldapUserResponse);
+            }
+
+            response.setResponses(ldapUserResponses);
+            response.setResponseName(getCommandName());
+            setResponseObject(response);
+        } catch (final NoLdapUserMatchingQueryException e) {
+            throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, e.getMessage());
+        }
+    }
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return 0;
+    }
+
+    public String getQuery() {
+        return query;
+    }
+
+    public void setQuery(final String query) {
+        this.query = query;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LdapConfigurationResponse.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..12c6ed9
--- /dev/null
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LdapConfigurationResponse.java
@@ -0,0 +1,46 @@
+package org.apache.cloudstack.api.response;
+
+import com.google.gson.annotations.SerializedName;
+
+import org.apache.cloudstack.api.BaseResponse;
+
+import com.cloud.serializer.Param;
+
+public class LdapConfigurationResponse extends BaseResponse {
+    @SerializedName("hostname")
+    @Param(description = "hostname")
+    private String hostname;
+
+    @SerializedName("port")
+    @Param(description = "port")
+    private int port;
+
+    public LdapConfigurationResponse() {
+        super();
+    }
+
+    public LdapConfigurationResponse(final String hostname) {
+        this.hostname = hostname;
+    }
+
+    public LdapConfigurationResponse(final String hostname, final int port) {
+        this.hostname = hostname;
+        this.port = port;
+    }
+
+    public String getHostname() {
+        return hostname;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setHostname(final String hostname) {
+        this.hostname = hostname;
+    }
+
+    public void setPort(final int port) {
+        this.port = port;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LdapUserResponse.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LdapUserResponse.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LdapUserResponse.java
new file mode 100644
index 0000000..24d8b4d
--- /dev/null
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/response/LdapUserResponse.java
@@ -0,0 +1,68 @@
+package org.apache.cloudstack.api.response;
+
+import com.google.gson.annotations.SerializedName;
+
+import org.apache.cloudstack.api.BaseResponse;
+
+import com.cloud.serializer.Param;
+
+public class LdapUserResponse extends BaseResponse {
+    @SerializedName("email")
+    @Param(description = "The user's email")
+    private String email;
+
+    @SerializedName("principal")
+    @Param(description = "The user's principle")
+    private String principal;
+
+    @SerializedName("realname")
+    @Param(description = "The user's realname")
+    private String realname;
+
+    @SerializedName("username")
+    @Param(description = "The user's username")
+    private String username;
+
+    public LdapUserResponse() {
+        super();
+    }
+
+    public LdapUserResponse(final String username, final String email, final String realname, final String principal) {
+        this.username = username;
+        this.email = email;
+        this.realname = realname;
+        this.principal = principal;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public String getPrincipal() {
+        return principal;
+    }
+
+    public String getRealname() {
+        return realname;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setEmail(final String email) {
+        this.email = email;
+    }
+
+    public void setPrincipal(final String principal) {
+        this.principal = principal;
+    }
+
+    public void setRealname(final String realname) {
+        this.realname = realname;
+    }
+
+    public void setUsername(final String username) {
+        this.username = username;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..74a15b6
--- /dev/null
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java
@@ -0,0 +1,53 @@
+package org.apache.cloudstack.ldap;
+
+import java.util.Map;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.command.LdapListConfigurationCmd;
+
+import com.cloud.server.auth.DefaultUserAuthenticator;
+import com.cloud.user.UserAccount;
+import com.cloud.user.dao.UserAccountDao;
+
+public class LdapAuthenticator extends DefaultUserAuthenticator {
+    private static final Logger s_logger = Logger.getLogger(LdapAuthenticator.class.getName());
+
+    @Inject
+    private LdapManager _ldapManager;
+    @Inject
+    private UserAccountDao _userAccountDao;
+
+    public LdapAuthenticator() {
+        super();
+    }
+
+    public LdapAuthenticator(final LdapManager ldapManager, final UserAccountDao userAccountDao) {
+        super();
+        _ldapManager = ldapManager;
+        _userAccountDao = userAccountDao;
+    }
+
+    @Override
+    public boolean authenticate(final String username, final String password, final Long domainId, final Map<String, Object[]> requestParameters) {
+
+        final UserAccount user = _userAccountDao.getUserAccount(username, domainId);
+
+        if (user == null) {
+            s_logger.debug("Unable to find user with " + username + " in domain " + domainId);
+            return false;
+        } else if (_ldapManager.listConfigurations(new LdapListConfigurationCmd(_ldapManager)).second() > 0) {
+            return _ldapManager.canAuthenticate(username, password);
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public String encode(final String password) {
+        return password;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapConfiguration.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..07d4879
--- /dev/null
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapConfiguration.java
@@ -0,0 +1,102 @@
+package org.apache.cloudstack.ldap;
+
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.naming.directory.SearchControls;
+
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.command.LdapListConfigurationCmd;
+
+import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.utils.Pair;
+
+public class LdapConfiguration {
+    private final static String factory = "com.sun.jndi.ldap.LdapCtxFactory";
+
+    private final static int scope = SearchControls.SUBTREE_SCOPE;
+
+    @Inject
+    private ConfigurationDao _configDao;
+
+    @Inject
+    private LdapManager _ldapManager;
+
+    public LdapConfiguration() {
+    }
+
+    public LdapConfiguration(final ConfigurationDao configDao, final LdapManager ldapManager) {
+        _configDao = configDao;
+        _ldapManager = ldapManager;
+    }
+
+    public String getAuthentication() {
+        if ((getBindPrincipal() == null) && (getBindPassword() == null)) {
+            return "none";
+        } else {
+            return "simple";
+        }
+    }
+
+    public String getBaseDn() {
+        return _configDao.getValue("ldap.basedn");
+    }
+
+    public String getBindPassword() {
+        return _configDao.getValue("ldap.bind.password");
+    }
+
+    public String getBindPrincipal() {
+        return _configDao.getValue("ldap.bind.principal");
+    }
+
+    public String getEmailAttribute() {
+        final String emailAttribute = _configDao.getValue("ldap.email.attribute");
+        return emailAttribute == null ? "mail" : emailAttribute;
+    }
+
+    public String getFactory() {
+        return factory;
+    }
+
+    public String getProviderUrl() {
+        final Pair<List<? extends LdapConfigurationVO>, Integer> result = _ldapManager
+                .listConfigurations(new LdapListConfigurationCmd(_ldapManager));
+        if (result.second() > 0) {
+            final StringBuilder providerUrls = new StringBuilder();
+            String delim = "";
+            for (final LdapConfigurationVO resource : result.first()) {
+                final String providerUrl = "ldap://" + resource.getHostname() + ":" + resource.getPort();
+                providerUrls.append(delim).append(providerUrl);
+                delim = " ";
+            }
+            return providerUrls.toString();
+        } else {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to get Ldap Configuration(s)");
+        }
+    }
+
+    public String getRealnameAttribute() {
+        final String realnameAttribute = _configDao.getValue("ldap.realname.attribute");
+        return realnameAttribute == null ? "cn" : realnameAttribute;
+    }
+
+    public String[] getReturnAttributes() {
+        return new String[] {getUsernameAttribute(), getEmailAttribute(), getRealnameAttribute()};
+    }
+
+    public int getScope() {
+        return scope;
+    }
+
+    public String getUsernameAttribute() {
+        final String usernameAttribute = _configDao.getValue("ldap.username.attribute");
+        return usernameAttribute == null ? "uid" : usernameAttribute;
+    }
+
+    public String getUserObject() {
+        final String userObject = _configDao.getValue("ldap.user.object");
+        return userObject == null ? "inetOrgPerson" : userObject;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapConfigurationVO.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..e7fe0a9
--- /dev/null
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapConfigurationVO.java
@@ -0,0 +1,58 @@
+package org.apache.cloudstack.ldap;
+
+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 org.apache.cloudstack.api.InternalIdentity;
+
+@Entity
+@Table(name = "ldap_configuration")
+public class LdapConfigurationVO implements InternalIdentity {
+    @Column(name = "hostname")
+    private String hostname;
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id")
+    private Long id;
+
+    @Column(name = "port")
+    private int port;
+
+    public LdapConfigurationVO() {
+    }
+
+    public LdapConfigurationVO(final String hostname, final int port) {
+        this.hostname = hostname;
+        this.port = port;
+    }
+
+    public String getHostname() {
+        return hostname;
+    }
+
+    @Override
+    public long getId() {
+        return id;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setHostname(final String hostname) {
+        this.hostname = hostname;
+    }
+
+    public void setId(final long id) {
+        this.id = id;
+    }
+
+    public void setPort(final int port) {
+        this.port = port;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapContextFactory.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..918fd20
--- /dev/null
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapContextFactory.java
@@ -0,0 +1,89 @@
+package org.apache.cloudstack.ldap;
+
+import java.util.Hashtable;
+
+import javax.inject.Inject;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.ldap.InitialLdapContext;
+import javax.naming.ldap.LdapContext;
+
+import org.apache.log4j.Logger;
+
+public class LdapContextFactory {
+    private static final Logger s_logger = Logger.getLogger(LdapContextFactory.class.getName());
+
+    @Inject
+    private LdapConfiguration _ldapConfiguration;
+
+    public LdapContextFactory() {
+    }
+
+    public LdapContextFactory(final LdapConfiguration ldapConfiguration) {
+        _ldapConfiguration = ldapConfiguration;
+    }
+
+    public LdapContext createBindContext() throws NamingException {
+        return createBindContext(null);
+    }
+
+    public LdapContext createBindContext(final String providerUrl) throws NamingException {
+        final String bindPrincipal = _ldapConfiguration.getBindPrincipal();
+        final String bindPassword = _ldapConfiguration.getBindPassword();
+        return createInitialDirContext(bindPrincipal, bindPassword, providerUrl, true);
+    }
+
+    private LdapContext createInitialDirContext(final String principal, final String password, final boolean isSystemContext)
+            throws NamingException {
+        return createInitialDirContext(principal, password, null, isSystemContext);
+    }
+
+    private LdapContext createInitialDirContext(final String principal, final String password, final String providerUrl, final boolean isSystemContext)
+            throws NamingException {
+        return new InitialLdapContext(getEnvironment(principal, password, providerUrl, isSystemContext), null);
+    }
+
+    public LdapContext createUserContext(final String principal, final String password) throws NamingException {
+        return createInitialDirContext(principal, password, false);
+    }
+
+    private Hashtable<String, String> getEnvironment(final String principal, final String password, final String providerUrl, final boolean isSystemContext) {
+        final String factory = _ldapConfiguration.getFactory();
+        final String url = providerUrl == null ? _ldapConfiguration.getProviderUrl() : providerUrl;
+        final String authentication = _ldapConfiguration.getAuthentication();
+
+        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", "1000");
+        environment.put("com.sun.jndi.ldap.connect.pool", "true");
+
+        if ("none".equals(authentication) && !isSystemContext) {
+            environment.put(Context.SECURITY_AUTHENTICATION, "simple");
+        } else {
+            environment.put(Context.SECURITY_AUTHENTICATION, authentication);
+        }
+
+        if (principal != null) {
+            environment.put(Context.SECURITY_PRINCIPAL, principal);
+        }
+
+        if (password != null) {
+            environment.put(Context.SECURITY_CREDENTIALS, password);
+        }
+
+        return environment;
+    }
+
+    public void testConnection(final String providerUrl) throws NamingException {
+        try {
+            createBindContext(providerUrl);
+            s_logger.info("LDAP Connection was successful");
+        } catch (final NamingException e) {
+            s_logger.warn("LDAP Connection failed");
+            s_logger.error(e.getMessage(), e);
+            throw e;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a90affe4/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapManager.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..980beb7
--- /dev/null
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapManager.java
@@ -0,0 +1,30 @@
+package org.apache.cloudstack.ldap;
+
+import java.util.List;
+
+import org.apache.cloudstack.api.command.LdapListConfigurationCmd;
+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;
+
+public interface LdapManager extends PluggableService {
+
+    LdapConfigurationResponse addConfiguration(String hostname, int port) throws InvalidParameterValueException;
+
+    boolean canAuthenticate(String username, String password);
+
+    LdapConfigurationResponse createLdapConfigurationResponse(LdapConfigurationVO configuration);
+
+    LdapUserResponse createLdapUserResponse(LdapUser user);
+
+    LdapConfigurationResponse deleteConfiguration(String hostname) throws InvalidParameterValueException;
+
+    List<LdapUser> getUsers() throws NoLdapUserMatchingQueryException;
+
+    Pair<List<? extends LdapConfigurationVO>, Integer> listConfigurations(LdapListConfigurationCmd cmd);
+
+    List<LdapUser> searchUsers(String query) throws NoLdapUserMatchingQueryException;
+}
\ No newline at end of file