Updated Branches:
  refs/heads/master 856703cc1 -> b436a8239

added group and domain params to importLdapUsers api call

Signed-off-by: Ian Duffy <[email protected]>


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

Branch: refs/heads/master
Commit: b436a82392111bd5052c6a1cfaa77174856d55f5
Parents: 856703c
Author: Rajani Karuturi <[email protected]>
Authored: Thu Oct 31 18:44:01 2013 +0530
Committer: Ian Duffy <[email protected]>
Committed: Thu Oct 31 22:06:32 2013 +0000

----------------------------------------------------------------------
 .../api/command/LdapImportUsersCmd.java         |  52 ++++++--
 .../cloudstack/ldap/LdapConfiguration.java      |  10 ++
 .../org/apache/cloudstack/ldap/LdapManager.java |   2 +
 .../apache/cloudstack/ldap/LdapManagerImpl.java |  15 ++-
 .../apache/cloudstack/ldap/LdapUserManager.java |  65 +++++++++-
 .../ldap/LdapConfigurationSpec.groovy           |  33 +++++
 .../ldap/LdapCreateAccountCmdSpec.groovy        |   8 +-
 .../ldap/LdapImportUsersCmdSpec.groovy          | 124 ++++++++++++++++++-
 .../cloudstack/ldap/LdapManagerImplSpec.groovy  |  16 +++
 .../cloudstack/ldap/LdapUserManagerSpec.groovy  |  77 ++++++++++++
 server/src/com/cloud/configuration/Config.java  |   3 +
 setup/db/db/schema-421to430.sql                 |   5 +
 12 files changed, 392 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b436a823/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java
----------------------------------------------------------------------
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 f872247..063db0e 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
@@ -26,6 +26,7 @@ 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 org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
 import org.bouncycastle.util.encoders.Base64;
 
@@ -55,6 +56,15 @@ public class LdapImportUsersCmd extends BaseListCmd {
     @Parameter(name = ApiConstants.ACCOUNT_DETAILS, type = CommandType.MAP, 
description = "details for account used to store specific parameters")
     private Map<String, String> details;
 
+    @Parameter(name = ApiConstants.DOMAIN, type = CommandType.STRING,
+              description = "Specifies the domain to which the ldap users are 
to be imported. If no domain is specified, a domain will created using group 
parameter. If the " +
+                  "group is also not specified, a domain name based on the OU 
information will be created. If no OU hierarchy exists, will be defaulted to 
ROOT domain")
+    private String domainName;
+
+    @Parameter(name = ApiConstants.GROUP, type = CommandType.STRING,
+              description = "Specifies the group name from which the ldap 
users are to be imported. If no group is specified, all the users will be 
imported.")
+    private String groupName;
+
     @Inject
     private LdapManager _ldapManager;
 
@@ -75,14 +85,15 @@ public class LdapImportUsersCmd extends BaseListCmd {
        List<LdapUserResponse> ldapResponses = null;
        final ListResponse<LdapUserResponse> response = new 
ListResponse<LdapUserResponse>();
        try {
-           final List<LdapUser> users = _ldapManager.getUsers();
+       List<LdapUser> users;
+       if(StringUtils.isNotBlank(groupName)) {
+           users = _ldapManager.getUsersInGroup(groupName);
+       } else {
+               users = _ldapManager.getUsers();
+       }
            for (LdapUser user : users) {
-               Domain domain = 
_domainService.getDomainByName(user.getDomain(), Domain.ROOT_DOMAIN);
-
-               if (domain == null) {
-                   domain = _domainService.createDomain(user.getDomain(), 
Domain.ROOT_DOMAIN, user.getDomain(), UUID.randomUUID().toString());
-               }
-               _accountService.createUserAccount(user.getUsername(), 
generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), 
timezone, user.getUsername(),
+           Domain domain = getDomain(user);
+                   _accountService.createUserAccount(user.getUsername(), 
generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), 
timezone, user.getUsername(),
                                                  accountType, domain.getId(), 
domain.getNetworkDomain(), details, UUID.randomUUID().toString(), 
UUID.randomUUID().toString());
            }
            ldapResponses = createLdapUserResponse(users);
@@ -95,6 +106,33 @@ public class LdapImportUsersCmd extends BaseListCmd {
        }
     }
 
+    private Domain getDomain(LdapUser user) {
+       String csDomainName = null;
+       if (StringUtils.isNotBlank(domainName)) {
+           csDomainName = domainName;
+       } else {
+           if (StringUtils.isNotBlank(groupName)) {
+               csDomainName = groupName;
+           } else if (StringUtils.isNotBlank(user.getDomain())) {
+               csDomainName = user.getDomain();
+           }
+           //removing all the special characters and trimming it length 190 to 
make the domain valid.
+           csDomainName = 
StringUtils.substring(csDomainName.replaceAll("\\W",""),0,190);
+       }
+       Domain domain;
+       if (StringUtils.isNotBlank(csDomainName)) {
+           domain = _domainService.getDomainByName(csDomainName, 
Domain.ROOT_DOMAIN);
+
+           if (domain == null) {
+               domain = _domainService.createDomain(csDomainName, 
Domain.ROOT_DOMAIN, csDomainName, UUID.randomUUID().toString());
+           }
+       } else {
+           domain = _domainService.getDomain(Domain.ROOT_DOMAIN);
+       }
+
+       return domain;
+    }
+
     private List<LdapUserResponse> createLdapUserResponse(List<LdapUser> 
users) {
        final List<LdapUserResponse> ldapResponses = new 
ArrayList<LdapUserResponse>();
        for (final LdapUser user : users) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b436a823/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
index a08dccb..7db55f7 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
@@ -143,6 +143,16 @@ public class LdapConfiguration {
                return userObject == null ? "inetOrgPerson" : userObject;
        }
 
+    public String getGroupObject() {
+       final String groupObject = _configDao.getValue("ldap.group.object");
+       return groupObject == null ? "groupOfUniqueNames" : groupObject;
+    }
+
+    public String getGroupUniqueMemeberAttribute() {
+       final String uniqueMemberAttribute = 
_configDao.getValue("ldap.group.user.uniquemember");
+       return uniqueMemberAttribute == null ? "uniquemember" : 
uniqueMemberAttribute;
+    }
+
     public String getCommonNameAttribute() {
        return "cn";
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b436a823/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
index 683822d..2c99d08 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
@@ -47,6 +47,8 @@ public interface LdapManager extends PluggableService {
 
        List<LdapUser> getUsers() throws NoLdapUserMatchingQueryException;
 
+    List<LdapUser> getUsersInGroup(String groupName) throws 
NoLdapUserMatchingQueryException;
+
        boolean isLdapEnabled();
 
        Pair<List<? extends LdapConfigurationVO>, Integer> listConfigurations(

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b436a823/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapManagerImpl.java
----------------------------------------------------------------------
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 90a79b3..891d625 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
@@ -194,7 +194,20 @@ public class LdapManagerImpl implements LdapManager, 
LdapValidator {
                }
        }
 
-       @Override
+    @Override
+    public List<LdapUser> getUsersInGroup(String groupName) throws 
NoLdapUserMatchingQueryException {
+       DirContext context = null;
+       try {
+           context = _ldapContextFactory.createBindContext();
+           return _ldapUserManager.getUsersInGroup(groupName, context);
+       } catch (final NamingException e) {
+           throw new NoLdapUserMatchingQueryException("groupName=" + 
groupName);
+       } finally {
+           closeContext(context);
+       }
+    }
+
+    @Override
        public boolean isLdapEnabled() {
                return listConfigurations(new 
LdapListConfigurationCmd(this)).second() > 0;
        }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b436a823/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapUserManager.java
----------------------------------------------------------------------
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 47697c9..59a41de 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
@@ -23,10 +23,7 @@ import java.util.List;
 import javax.inject.Inject;
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.SearchControls;
-import javax.naming.directory.SearchResult;
+import javax.naming.directory.*;
 
 public class LdapUserManager {
 
@@ -86,6 +83,28 @@ public class LdapUserManager {
        return result.toString();
     }
 
+    private String generateGroupSearchFilter(final String groupName) {
+       final StringBuilder groupObjectFilter = new StringBuilder();
+       groupObjectFilter.append("(objectClass=");
+       groupObjectFilter.append(_ldapConfiguration.getGroupObject());
+       groupObjectFilter.append(")");
+
+       final StringBuilder groupNameFilter = new StringBuilder();
+       groupNameFilter.append("(");
+       groupNameFilter.append(_ldapConfiguration.getCommonNameAttribute());
+       groupNameFilter.append("=");
+       groupNameFilter.append((groupName == null ? "*" : groupName));
+       groupNameFilter.append(")");
+
+       final StringBuilder result = new StringBuilder();
+       result.append("(&");
+       result.append(groupObjectFilter);
+       result.append(groupNameFilter);
+       result.append(")");
+
+       return result.toString();
+    }
+
     public LdapUser getUser(final String username, final DirContext context) 
throws NamingException {
        final NamingEnumeration<SearchResult> result = searchUsers(username, 
context);
        if (result.hasMoreElements()) {
@@ -114,6 +133,44 @@ public class LdapUserManager {
        return users;
     }
 
+    public List<LdapUser> getUsersInGroup(String groupName, DirContext 
context) throws NamingException {
+       String attributeName = 
_ldapConfiguration.getGroupUniqueMemeberAttribute();
+       final SearchControls controls = new SearchControls();
+       controls.setSearchScope(_ldapConfiguration.getScope());
+       controls.setReturningAttributes(new String[]{attributeName});
+
+       NamingEnumeration<SearchResult> result = 
context.search(_ldapConfiguration.getBaseDn(), 
generateGroupSearchFilter(groupName), controls);
+
+       final List<LdapUser> users = new ArrayList<LdapUser>();
+       //Expecting only one result which has all the users
+       if (result.hasMoreElements()) {
+           Attribute attribute = 
result.nextElement().getAttributes().get(attributeName);
+           NamingEnumeration<?> values = attribute.getAll();
+
+           while (values.hasMoreElements()) {
+               String userdn = String.valueOf(values.nextElement());
+               users.add(getUserForDn(userdn,context));
+           }
+       }
+
+       Collections.sort(users);
+
+       return users;
+    }
+
+    private LdapUser getUserForDn(String userdn, DirContext context) throws 
NamingException {
+       final SearchControls controls = new SearchControls();
+       controls.setSearchScope(_ldapConfiguration.getScope());
+       
controls.setReturningAttributes(_ldapConfiguration.getReturnAttributes());
+
+       NamingEnumeration<SearchResult> result = context.search(userdn, 
"(objectClass="+_ldapConfiguration.getUserObject()+")", controls);
+       if (result.hasMoreElements()) {
+           return createUser(result.nextElement());
+       } else {
+           throw new NamingException("No user found for dn " + userdn);
+       }
+    }
+
     public NamingEnumeration<SearchResult> searchUsers(final DirContext 
context) throws NamingException {
        return searchUsers(null, context);
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b436a823/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapConfigurationSpec.groovy
----------------------------------------------------------------------
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 66b4673..1017a0f 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
@@ -220,4 +220,37 @@ class LdapConfigurationSpec extends 
spock.lang.Specification {
                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 ldapManger = Mock(LdapManager)
+       LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, 
ldapManger)
+       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 ldapManger = Mock(LdapManager)
+       LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, 
ldapManger)
+       def expectedResult = groupObject == null ? "uniquemember" : groupObject
+
+       def result = ldapConfiguration.getGroupUniqueMemeberAttribute()
+       expect:
+       result == expectedResult
+       where:
+       groupObject << [null, "", "uniquemember"]
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b436a823/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapCreateAccountCmdSpec.groovy
----------------------------------------------------------------------
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 cc849de..b316a80 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
@@ -52,7 +52,7 @@ class LdapCreateAccountCmdSpec extends 
spock.lang.Specification {
        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", 
"[email protected]", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org")
+               ldapManager.getUser(_) >> new LdapUser("rmurphy", 
"[email protected]", "Ryan", "Murphy", 
"cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
                AccountService accountService = Mock(AccountService)
                def ldapCreateAccountCmd = Spy(LdapCreateAccountCmd, 
constructorArgs: [ldapManager, accountService])
                ldapCreateAccountCmd.getCurrentContext() >> Mock(CallContext)
@@ -104,7 +104,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"))
+               def result = ldapCreateAccountCmd.validateUser(new 
LdapUser("username","email","firstname","lastname","principal","domain"))
                then: "the result is true"
                result == true
    }
@@ -115,7 +115,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"))
+               ldapCreateAccountCmd.validateUser(new 
LdapUser("username",null,"firstname","lastname","principal","domain"))
                then: "An exception is thrown"
                thrown Exception
    }
@@ -137,7 +137,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"))
+               ldapCreateAccountCmd.validateUser(new 
LdapUser("username","email","firstname",null,"principal","domain"))
                then: "An exception is thown"
                thrown Exception
    }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b436a823/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy
----------------------------------------------------------------------
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 d04b094..0455640 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
@@ -34,7 +34,8 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification 
{
        given: "We have an LdapManager, DomainService and a LdapImportUsersCmd"
        def ldapManager = Mock(LdapManager)
        def domainService = Mock(DomainService)
-       def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, 
domainService)
+    def accountService = Mock(AccountService)
+       def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, 
domainService, accountService)
        when: "Get command name is called"
        String commandName = ldapImportUsersCmd.getCommandName()
        then: "ldapuserresponse is returned"
@@ -42,7 +43,7 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification 
{
     }
 
     def "Test successful response from execute"() {
-       given: "We have an LdapManager, DomainService, one user and a 
LdapImportUsersCmd"
+       given: "We have an LdapManager, DomainService, two users and a 
LdapImportUsersCmd"
        def ldapManager = Mock(LdapManager)
        def domainService = Mock(DomainService)
        def accountService = Mock(AccountService)
@@ -68,4 +69,123 @@ class LdapImportUsersCmdSpec extends 
spock.lang.Specification {
        then: "a list of size 2 is returned"
        ldapImportUsersCmd.responseObject.getResponses().size() == 2
     }
+
+    def "Test successful response from execute with group specified"() {
+       given: "We have an LdapManager, DomainService, two users and a 
LdapImportUsersCmd"
+       def ldapManager = Mock(LdapManager)
+       def domainService = Mock(DomainService)
+       def accountService = Mock(AccountService)
+
+       List<LdapUser> users = new ArrayList()
+       users.add(new LdapUser("rmurphy", "[email protected]", "Ryan", "Murphy", 
"cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering"))
+       users.add(new LdapUser("bob", "[email protected]", "Robert", "Young", 
"cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering"))
+       ldapManager.getUsersInGroup("TestGroup") >> users
+       LdapUserResponse response1 = new LdapUserResponse("rmurphy", 
"[email protected]", "Ryan", "Murphy", 
"cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
+       LdapUserResponse response2 = new LdapUserResponse("bob", 
"[email protected]", "Robert", "Young", 
"cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")
+       ldapManager.createLdapUserResponse(_) >>>[response1, response2]
+
+
+       Domain domain = new DomainVO("TestGroup", 1L, 1L, "TestGroup", 
UUID.randomUUID().toString())
+       domainService.getDomainByName("TestGroup", 1L) >>> [null, domain]
+       1 * domainService.createDomain("TestGroup", 1L, "TestGroup", _) >> 
domain
+
+       def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, 
domainService, accountService)
+       ldapImportUsersCmd.accountType = 2;
+       ldapImportUsersCmd.groupName = "TestGroup";
+
+       when: "LdapListUsersCmd is executed"
+       ldapImportUsersCmd.execute()
+       then: "a list of size 2 is returned"
+       ldapImportUsersCmd.responseObject.getResponses().size() == 2
+    }
+
+    def "Test successful response from execute with group and domain 
specified"() {
+       given: "We have an LdapManager, DomainService, two users and a 
LdapImportUsersCmd"
+       def ldapManager = Mock(LdapManager)
+       def domainService = Mock(DomainService)
+       def accountService = Mock(AccountService)
+
+       List<LdapUser> users = new ArrayList()
+       users.add(new LdapUser("rmurphy", "[email protected]", "Ryan", "Murphy", 
"cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering"))
+       users.add(new LdapUser("bob", "[email protected]", "Robert", "Young", 
"cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering"))
+       ldapManager.getUsersInGroup("TestGroup") >> users
+       LdapUserResponse response1 = new LdapUserResponse("rmurphy", 
"[email protected]", "Ryan", "Murphy", 
"cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
+       LdapUserResponse response2 = new LdapUserResponse("bob", 
"[email protected]", "Robert", "Young", 
"cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")
+       ldapManager.createLdapUserResponse(_) >>>[response1, response2]
+
+
+       Domain domain = new DomainVO("TestDomain", 1L, 1L, "TestDomain", 
UUID.randomUUID().toString())
+       domainService.getDomainByName("TestDomain", 1L) >>> [null, domain]
+       1 * domainService.createDomain("TestDomain", 1L, "TestDomain", _) >> 
domain
+
+       def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, 
domainService, accountService)
+       ldapImportUsersCmd.accountType = 2;
+       ldapImportUsersCmd.groupName = "TestGroup";
+       ldapImportUsersCmd.domainName = "TestDomain";
+
+       when: "LdapListUsersCmd is executed"
+       ldapImportUsersCmd.execute()
+       then: "a list of size 2 is returned"
+       ldapImportUsersCmd.responseObject.getResponses().size() == 2
+    }
+
+    def "Test successful response from execute with domain specified"() {
+       given: "We have an LdapManager, DomainService, two users and a 
LdapImportUsersCmd"
+       def ldapManager = Mock(LdapManager)
+       def domainService = Mock(DomainService)
+       def accountService = Mock(AccountService)
+
+       List<LdapUser> users = new ArrayList()
+       users.add(new LdapUser("rmurphy", "[email protected]", "Ryan", "Murphy", 
"cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering"))
+       users.add(new LdapUser("bob", "[email protected]", "Robert", "Young", 
"cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering"))
+       ldapManager.getUsers() >> users
+       LdapUserResponse response1 = new LdapUserResponse("rmurphy", 
"[email protected]", "Ryan", "Murphy", 
"cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
+       LdapUserResponse response2 = new LdapUserResponse("bob", 
"[email protected]", "Robert", "Young", 
"cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")
+       ldapManager.createLdapUserResponse(_) >>>[response1, response2]
+
+
+       Domain domain = new DomainVO("TestDomain", 1L, 1L, "TestDomain", 
UUID.randomUUID().toString())
+       domainService.getDomainByName("TestDomain", 1L) >>> [null, domain]
+       1 * domainService.createDomain("TestDomain", 1L, "TestDomain", _) >> 
domain
+
+       def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, 
domainService, accountService)
+       ldapImportUsersCmd.accountType = 2;
+       ldapImportUsersCmd.domainName = "TestDomain";
+
+       when: "LdapListUsersCmd is executed"
+       ldapImportUsersCmd.execute()
+       then: "a list of size 2 is returned"
+       ldapImportUsersCmd.responseObject.getResponses().size() == 2
+    }
+
+    def "Test getDomain with no domain or group name specified specified"() {
+       given: "We have an LdapManager, DomainService, two users and a 
LdapImportUsersCmd"
+       def ldapManager = Mock(LdapManager)
+       def domainService = Mock(DomainService)
+       def accountService = Mock(AccountService)
+       def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, 
domainService, accountService)
+       ldapImportUsersCmd.domainName = varDomainName
+       ldapImportUsersCmd.groupName = varGroupName
+
+       def ldapUser1 = new LdapUser("rmurphy", "[email protected]", "Ryan", 
"Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
+       def ldapUser2 = new LdapUser("bob", "[email protected]", "Robert", "Young", 
"cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering");
+
+       Domain domain = new DomainVO(expectedDomainName, 1L, 1L, 
expectedDomainName, UUID.randomUUID().toString())
+       2 * domainService.getDomainByName(expectedDomainName, 1L) >>> [null, 
domain]
+       1 * domainService.createDomain(expectedDomainName, 1L, 
expectedDomainName, _) >> domain
+
+       def result1 = ldapImportUsersCmd.getDomain(ldapUser1)
+       def result2 = ldapImportUsersCmd.getDomain(ldapUser2)
+       expect: "engineering domain is returned"
+       result1 == domain
+       result2 == domain
+       where: "The domain and group are set to the following values"
+       varDomainName | varGroupName | expectedDomainName
+       null | null | "engineering"
+       "TestDomain" | null | "TestDomain"
+       "TestDomain" | "TestGroup" | "TestDomain"
+       null | "TestGroup" | "TestGroup"
+
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b436a823/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapManagerImplSpec.groovy
----------------------------------------------------------------------
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 321e1af..42988e0 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
@@ -356,4 +356,20 @@ class LdapManagerImplSpec extends spock.lang.Specification 
{
                then: "true is returned because a configuration was found"
                result == true;
        }
+
+    def "Test success getUsersInGroup"() {
+       given: "We have an LdapConfigurationDao, LdapContextFactory, 
LdapUserManager and LdapManager"
+       def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
+       def ldapContextFactory = Mock(LdapContextFactory)
+       def ldapUserManager = Mock(LdapUserManager)
+       ldapContextFactory.createBindContext() >> null
+       List<LdapUser> users = new ArrayList<>();
+       users.add(new LdapUser("rmurphy", "[email protected]", "Ryan", "Murphy", 
"cn=rmurphy,dc=cloudstack,dc=org", "engineering"))
+       ldapUserManager.getUsersInGroup("engineering", _) >> users;
+       def ldapManager = new LdapManagerImpl(ldapConfigurationDao, 
ldapContextFactory, ldapUserManager)
+       when: "We search for a group of users"
+       def result = ldapManager.getUsersInGroup("engineering")
+       then: "A list greater of size one is returned"
+       result.size() == 1;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b436a823/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapUserManagerSpec.groovy
----------------------------------------------------------------------
diff --git 
a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapUserManagerSpec.groovy
 
b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapUserManagerSpec.groovy
index 339923e..fa735d3 100644
--- 
a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapUserManagerSpec.groovy
+++ 
b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapUserManagerSpec.groovy
@@ -21,8 +21,10 @@ import org.apache.cloudstack.ldap.LdapUserManager
 import spock.lang.Shared
 
 import javax.naming.NamingException
+import javax.naming.NamingEnumeration
 import javax.naming.directory.Attribute
 import javax.naming.directory.Attributes
+import javax.naming.directory.DirContext
 import javax.naming.directory.SearchControls
 import javax.naming.directory.SearchResult
 import javax.naming.ldap.LdapContext
@@ -47,6 +49,38 @@ class LdapUserManagerSpec extends spock.lang.Specification {
     @Shared
     private def principal
 
+    private def createGroupSearchContext() {
+
+       def umSearchResult = Mock(SearchResult)
+       umSearchResult.getName() >> principal;
+       umSearchResult.getAttributes() >> principal
+
+       def uniqueMembers = new BasicNamingEnumerationImpl()
+       uniqueMembers.add(umSearchResult);
+       def attributes = Mock(Attributes)
+       def uniqueMemberAttribute = Mock(Attribute)
+       uniqueMemberAttribute.getId() >> "uniquemember"
+       uniqueMemberAttribute.getAll() >> uniqueMembers
+       attributes.get("uniquemember") >> uniqueMemberAttribute
+
+       def groupSearchResult = Mock(SearchResult)
+       groupSearchResult.getName() >> principal;
+       groupSearchResult.getAttributes() >> attributes
+
+       def searchGroupResults = new BasicNamingEnumerationImpl()
+       searchGroupResults.add(groupSearchResult);
+
+       attributes = createUserAttributes(username, email, firstname, lastname)
+       SearchResult userSearchResult = createSearchResult(attributes)
+       def searchUsersResults = new BasicNamingEnumerationImpl()
+       searchUsersResults.add(userSearchResult);
+
+       def context = Mock(LdapContext)
+       context.search(_, _, _) >>> [searchGroupResults, searchUsersResults];
+
+       return context
+    }
+
     private def createContext() {
                Attributes attributes = createUserAttributes(username, email, 
firstname, lastname)
                SearchResult searchResults = createSearchResult(attributes)
@@ -65,6 +99,7 @@ class LdapUserManagerSpec extends spock.lang.Specification {
                search.getName() >> "cn=" + attributes.getAt("uid").get();
 
                search.getAttributes() >> attributes
+       search.getNameInNamespace() >> principal
 
                return search
     }
@@ -105,6 +140,9 @@ class LdapUserManagerSpec extends spock.lang.Specification {
         ldapConfiguration.getFirstnameAttribute() >> "givenname"
         ldapConfiguration.getLastnameAttribute() >> "sn"
         ldapConfiguration.getBaseDn() >> "dc=cloudstack,dc=org"
+       ldapConfiguration.getCommonNameAttribute() >> "cn"
+       ldapConfiguration.getGroupObject() >> "groupOfUniqueNames"
+       ldapConfiguration.getGroupUniqueMemeberAttribute() >> "uniquemember"
 
         username = "rmurphy"
         email = "[email protected]"
@@ -203,4 +241,43 @@ class LdapUserManagerSpec extends spock.lang.Specification 
{
                expect: "The result is not null"
                result != null
     }
+
+    def "test successful generateGroupSearchFilter"() {
+       given: "ldap user manager and ldap config"
+       def ldapUserManager = new LdapUserManager(ldapConfiguration)
+       def groupName = varGroupName == null ? "*" : varGroupName
+       def expectedResult = 
"(&(objectClass=groupOfUniqueNames)(cn="+groupName+"))";
+
+       def result = ldapUserManager.generateGroupSearchFilter(varGroupName)
+       expect:
+       result == expectedResult
+       where: "The group name passed is set to "
+       varGroupName << ["", null, "Murphy"]
+    }
+
+    def "test successful getUsersInGroup"(){
+       given: "ldap user manager and ldap config"
+       def ldapUserManager = new LdapUserManager(ldapConfiguration)
+
+       when: "A request for users is made"
+       def result = ldapUserManager.getUsersInGroup("engineering", 
createGroupSearchContext())
+       then: "one user is returned"
+       result.size() == 1
+    }
+
+    def "test successful getUserForDn"(){
+       given: "ldap user manager and ldap config"
+       def ldapUserManager = new LdapUserManager(ldapConfiguration)
+
+       when: "A request for users is made"
+       def result = ldapUserManager.getUserForDn("cn=Ryan 
Murphy,ou=engineering,dc=cloudstack,dc=org",createContext())
+       then: "A list of users is returned"
+       result != 1
+       result.username == username
+       result.email == email
+       result.firstname == firstname
+       result.lastname == lastname
+       result.principal == principal
+
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b436a823/server/src/com/cloud/configuration/Config.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/Config.java 
b/server/src/com/cloud/configuration/Config.java
index 3fdc343..e787576 100755
--- a/server/src/com/cloud/configuration/Config.java
+++ b/server/src/com/cloud/configuration/Config.java
@@ -394,6 +394,9 @@ public enum Config {
     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),

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b436a823/setup/db/db/schema-421to430.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-421to430.sql b/setup/db/db/schema-421to430.sql
index 0de9dfd..1e803dc 100644
--- a/setup/db/db/schema-421to430.sql
+++ b/setup/db/db/schema-421to430.sql
@@ -483,3 +483,8 @@ ALTER TABLE `cloud`.`nic_details` CHANGE `display_detail` 
`display` tinyint(1) N
 ALTER TABLE `cloud`.`user_vm_details` CHANGE `display_detail` `display` 
tinyint(1) NOT NULL DEFAULT '0' COMMENT 'True if the detail can be displayed to 
the end user';
 ALTER TABLE `cloud`.`service_offering_details` ADD COLUMN `display` tinyint(1) 
NOT NULL DEFAULT '0' COMMENT 'True if the detail can be displayed to the end 
user';
 ALTER TABLE `cloud`.`storage_pool_details` ADD COLUMN `display` tinyint(1) NOT 
NULL DEFAULT '0' COMMENT 'True if the detail can be displayed to the end user';
+
+INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 
'management-server', 'ldap.group.object', 'groupOfUniqueNames',
+'Sets the object type of groups within LDAP','groupOfUniqueNames',NULL,NULL,0);
+INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 
'management-server', 'ldap.group.user.uniquemember', 'uniquemember',
+'Sets the attribute for uniquemembers within a 
group','uniquemember',NULL,NULL,0);

Reply via email to