diff --git a/plugins/user-authenticators/ldap/pom.xml b/plugins/user-authenticators/ldap/pom.xml index d24a5be5ab3..22cdeb722d6 100644 --- a/plugins/user-authenticators/ldap/pom.xml +++ b/plugins/user-authenticators/ldap/pom.xml @@ -24,7 +24,7 @@ org.codehaus.gmaven gmaven-plugin - 1.5 + 1.3 1.7 diff --git a/plugins/user-authenticators/ldap/resources/META-INF/cloudstack/ldap/spring-ldap-context.xml b/plugins/user-authenticators/ldap/resources/META-INF/cloudstack/ldap/spring-ldap-context.xml index 34a2befe971..8ae4009367f 100644 --- a/plugins/user-authenticators/ldap/resources/META-INF/cloudstack/ldap/spring-ldap-context.xml +++ b/plugins/user-authenticators/ldap/resources/META-INF/cloudstack/ldap/spring-ldap-context.xml @@ -30,7 +30,7 @@ - + diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/ADLdapUserManagerImpl.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/ADLdapUserManagerImpl.java new file mode 100644 index 00000000000..50f1fa00092 --- /dev/null +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/ADLdapUserManagerImpl.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.ldap; + +import java.util.ArrayList; +import java.util.List; + +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.SearchControls; +import javax.naming.directory.SearchResult; +import javax.naming.ldap.LdapContext; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; + +public class ADLdapUserManagerImpl extends OpenLdapUserManagerImpl implements LdapUserManager { + public static final Logger s_logger = Logger.getLogger(ADLdapUserManagerImpl.class.getName()); + private static final String MICROSOFT_AD_NESTED_MEMBERS_FILTER = "memberOf:1.2.840.113556.1.4.1941"; + + @Override + public List getUsersInGroup(String groupName, LdapContext context) throws NamingException { + if (StringUtils.isBlank(groupName)) { + throw new IllegalArgumentException("ldap group name cannot be blank"); + } + + String basedn = _ldapConfiguration.getBaseDn(); + if (StringUtils.isBlank(basedn)) { + throw new IllegalArgumentException("ldap basedn is not configured"); + } + + final SearchControls searchControls = new SearchControls(); + searchControls.setSearchScope(_ldapConfiguration.getScope()); + searchControls.setReturningAttributes(_ldapConfiguration.getReturnAttributes()); + + NamingEnumeration results = context.search(basedn, generateADGroupSearchFilter(groupName), searchControls); + final List users = new ArrayList(); + while (results.hasMoreElements()) { + final SearchResult result = results.nextElement(); + users.add(createUser(result)); + } + return users; + } + + private String generateADGroupSearchFilter(String groupName) { + final StringBuilder userObjectFilter = new StringBuilder(); + userObjectFilter.append("(objectClass="); + userObjectFilter.append(_ldapConfiguration.getUserObject()); + userObjectFilter.append(")"); + + final StringBuilder memberOfFilter = new StringBuilder(); + String groupCnName = _ldapConfiguration.getCommonNameAttribute() + "=" +groupName + "," + _ldapConfiguration.getBaseDn(); + memberOfFilter.append("(" + MICROSOFT_AD_NESTED_MEMBERS_FILTER + ":="); + memberOfFilter.append(groupCnName); + memberOfFilter.append(")"); + + final StringBuilder result = new StringBuilder(); + result.append("(&"); + result.append(userObjectFilter); + result.append(memberOfFilter); + result.append(")"); + + s_logger.debug("group search filter = " + result); + return result.toString(); + } +} 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 c171ebfcc0b..a64899af296 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 @@ -21,12 +21,12 @@ import java.util.List; import javax.inject.Inject; import javax.naming.directory.SearchControls; -import org.apache.cloudstack.api.command.LdapListConfigurationCmd; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import com.cloud.utils.Pair; +import org.apache.cloudstack.ldap.dao.LdapConfigurationDao; public class LdapConfiguration implements Configurable{ private final static String factory = "com.sun.jndi.ldap.LdapCtxFactory"; @@ -36,6 +36,8 @@ public class LdapConfiguration implements Configurable{ private static final ConfigKey ldapPageSize = new ConfigKey(Integer.class, "ldap.request.page.size", "Advanced", "1000", "page size sent to ldap server on each request to get user", true, ConfigKey.Scope.Global, 1); + private static final ConfigKey ldapProvider = new ConfigKey(String.class, "ldap.provider", "Advanced", "openldap", "ldap provider ex:openldap, microsoftad", + true, ConfigKey.Scope.Global, null); private final static int scope = SearchControls.SUBTREE_SCOPE; @@ -43,14 +45,14 @@ public class LdapConfiguration implements Configurable{ private ConfigurationDao _configDao; @Inject - private LdapManager _ldapManager; + private LdapConfigurationDao _ldapConfigurationDao; public LdapConfiguration() { } - public LdapConfiguration(final ConfigurationDao configDao, final LdapManager ldapManager) { + public LdapConfiguration(final ConfigurationDao configDao, final LdapConfigurationDao ldapConfigurationDao) { _configDao = configDao; - _ldapManager = ldapManager; + _ldapConfigurationDao = ldapConfigurationDao; } public String getAuthentication() { @@ -94,7 +96,7 @@ public class LdapConfiguration implements Configurable{ public String getProviderUrl() { final String protocol = getSSLStatus() == true ? "ldaps://" : "ldap://"; - final Pair, Integer> result = _ldapManager.listConfigurations(new LdapListConfigurationCmd(_ldapManager)); + final Pair, Integer> result = _ldapConfigurationDao.searchConfigurations(null, 0); final StringBuilder providerUrls = new StringBuilder(); String delim = ""; for (final LdapConfigurationVO resource : result.first()) { @@ -165,6 +167,17 @@ public class LdapConfiguration implements Configurable{ return ldapPageSize.value(); } + public LdapUserManager.Provider getLdapProvider() { + LdapUserManager.Provider provider; + try { + provider = LdapUserManager.Provider.valueOf(ldapProvider.value().toUpperCase()); + } catch (IllegalArgumentException ex) { + //openldap is the default + provider = LdapUserManager.Provider.OPENLDAP; + } + return provider; + } + @Override public String getConfigComponentName() { return LdapConfiguration.class.getSimpleName(); @@ -172,6 +185,6 @@ public class LdapConfiguration implements Configurable{ @Override public ConfigKey[] getConfigKeys() { - return new ConfigKey[] {ldapReadTimeout, ldapPageSize}; + return new ConfigKey[] {ldapReadTimeout, ldapPageSize, ldapProvider}; } } \ No newline at end of file diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapManagerImpl.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapManagerImpl.java index dfd39a3c7c1..8e912b8b030 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 @@ -57,17 +57,22 @@ public class LdapManagerImpl implements LdapManager, LdapValidator { private LdapContextFactory _ldapContextFactory; @Inject - private LdapUserManager _ldapUserManager; + private LdapConfiguration _ldapConfiguration; + + @Inject LdapUserManagerFactory _ldapUserManagerFactory; + public LdapManagerImpl() { super(); } - public LdapManagerImpl(final LdapConfigurationDao ldapConfigurationDao, final LdapContextFactory ldapContextFactory, final LdapUserManager ldapUserManager) { + public LdapManagerImpl(final LdapConfigurationDao ldapConfigurationDao, final LdapContextFactory ldapContextFactory, final LdapUserManagerFactory ldapUserManagerFactory, + final LdapConfiguration ldapConfiguration) { super(); _ldapConfigurationDao = ldapConfigurationDao; _ldapContextFactory = ldapContextFactory; - _ldapUserManager = ldapUserManager; + _ldapUserManagerFactory = ldapUserManagerFactory; + _ldapConfiguration = ldapConfiguration; } @Override @@ -173,7 +178,7 @@ public class LdapManagerImpl implements LdapManager, LdapValidator { context = _ldapContextFactory.createBindContext(); final String escapedUsername = LdapUtils.escapeLDAPSearchFilter(username); - return _ldapUserManager.getUser(escapedUsername, context); + return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider()).getUser(escapedUsername, context); } catch (NamingException | IOException e) { s_logger.debug("ldap Exception: ",e); @@ -188,7 +193,7 @@ public class LdapManagerImpl implements LdapManager, LdapValidator { LdapContext context = null; try { context = _ldapContextFactory.createBindContext(); - return _ldapUserManager.getUsers(context); + return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider()).getUsers(context); } catch (NamingException | IOException e) { s_logger.debug("ldap Exception: ",e); throw new NoLdapUserMatchingQueryException("*"); @@ -202,7 +207,7 @@ public class LdapManagerImpl implements LdapManager, LdapValidator { LdapContext context = null; try { context = _ldapContextFactory.createBindContext(); - return _ldapUserManager.getUsersInGroup(groupName, context); + return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider()).getUsersInGroup(groupName, context); } catch (NamingException | IOException e) { s_logger.debug("ldap NamingException: ",e); throw new NoLdapUserMatchingQueryException("groupName=" + groupName); @@ -230,7 +235,7 @@ public class LdapManagerImpl implements LdapManager, LdapValidator { try { context = _ldapContextFactory.createBindContext(); final String escapedUsername = LdapUtils.escapeLDAPSearchFilter(username); - return _ldapUserManager.getUsers("*" + escapedUsername + "*", context); + return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider()).getUsers("*" + escapedUsername + "*", context); } catch (NamingException | IOException e) { s_logger.debug("ldap Exception: ",e); throw new NoLdapUserMatchingQueryException(username); 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 654a601a476..c1bfe742616 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 @@ -1,227 +1,44 @@ -// 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. +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package org.apache.cloudstack.ldap; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import javax.inject.Inject; -import javax.naming.NamingEnumeration; import javax.naming.NamingException; -import javax.naming.directory.Attribute; -import javax.naming.directory.Attributes; -import javax.naming.directory.SearchControls; -import javax.naming.directory.SearchResult; -import javax.naming.ldap.Control; import javax.naming.ldap.LdapContext; -import javax.naming.ldap.PagedResultsControl; -import javax.naming.ldap.PagedResultsResponseControl; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; +public interface LdapUserManager { -public class LdapUserManager { - private static final Logger s_logger = Logger.getLogger(LdapUserManager.class.getName()); - - @Inject - private LdapConfiguration _ldapConfiguration; - - public LdapUserManager() { + public enum Provider { + MICROSOFTAD, OPENLDAP; } - public LdapUserManager(final LdapConfiguration ldapConfiguration) { - _ldapConfiguration = ldapConfiguration; - } + public LdapUser getUser(final String username, final LdapContext context) throws NamingException, IOException; - private LdapUser createUser(final SearchResult result) throws NamingException { - final Attributes attributes = result.getAttributes(); + public List getUsers(final LdapContext context) throws NamingException, IOException; - final String username = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getUsernameAttribute()); - final String email = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getEmailAttribute()); - final String firstname = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getFirstnameAttribute()); - final String lastname = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getLastnameAttribute()); - final String principal = result.getNameInNamespace(); + public List getUsers(final String username, final LdapContext context) throws NamingException, IOException; - String domain = principal.replace("cn=" + LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getCommonNameAttribute()) + ",", ""); - domain = domain.replace("," + _ldapConfiguration.getBaseDn(), ""); - domain = domain.replace("ou=", ""); + public List getUsersInGroup(String groupName, LdapContext context) throws NamingException; - return new LdapUser(username, email, firstname, lastname, principal, domain); - } + public List searchUsers(final LdapContext context) throws NamingException, IOException; - private String generateSearchFilter(final String username) { - final StringBuilder userObjectFilter = new StringBuilder(); - userObjectFilter.append("(objectClass="); - userObjectFilter.append(_ldapConfiguration.getUserObject()); - userObjectFilter.append(")"); - - final StringBuilder usernameFilter = new StringBuilder(); - usernameFilter.append("("); - usernameFilter.append(_ldapConfiguration.getUsernameAttribute()); - usernameFilter.append("="); - usernameFilter.append((username == null ? "*" : username)); - usernameFilter.append(")"); - - final StringBuilder memberOfFilter = new StringBuilder(); - if (_ldapConfiguration.getSearchGroupPrinciple() != null) { - memberOfFilter.append("(memberof="); - memberOfFilter.append(_ldapConfiguration.getSearchGroupPrinciple()); - memberOfFilter.append(")"); - } - - final StringBuilder result = new StringBuilder(); - result.append("(&"); - result.append(userObjectFilter); - result.append(usernameFilter); - result.append(memberOfFilter); - result.append(")"); - - 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 LdapContext context) throws NamingException, IOException { - List result = searchUsers(username, context); - if (result!= null && result.size() == 1) { - return result.get(0); - } else { - throw new NamingException("No user found for username " + username); - } - } - - public List getUsers(final LdapContext context) throws NamingException, IOException { - return getUsers(null, context); - } - - public List getUsers(final String username, final LdapContext context) throws NamingException, IOException { - List users = searchUsers(username, context); - - if (CollectionUtils.isNotEmpty(users)) { - Collections.sort(users); - } - return users; - } - - public List getUsersInGroup(String groupName, LdapContext context) throws NamingException { - String attributeName = _ldapConfiguration.getGroupUniqueMemeberAttribute(); - final SearchControls controls = new SearchControls(); - controls.setSearchScope(_ldapConfiguration.getScope()); - controls.setReturningAttributes(new String[] {attributeName}); - - NamingEnumeration result = context.search(_ldapConfiguration.getBaseDn(), generateGroupSearchFilter(groupName), controls); - - final List users = new ArrayList(); - //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()); - try{ - users.add(getUserForDn(userdn, context)); - } catch (NamingException e){ - s_logger.info("Userdn: " + userdn + " Not Found:: Exception message: " + e.getMessage()); - } - } - } - - Collections.sort(users); - - return users; - } - - private LdapUser getUserForDn(String userdn, LdapContext context) throws NamingException { - final SearchControls controls = new SearchControls(); - controls.setSearchScope(_ldapConfiguration.getScope()); - controls.setReturningAttributes(_ldapConfiguration.getReturnAttributes()); - - NamingEnumeration 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 List searchUsers(final LdapContext context) throws NamingException, IOException { - return searchUsers(null, context); - } - - public List searchUsers(final String username, final LdapContext context) throws NamingException, IOException { - - final SearchControls searchControls = new SearchControls(); - - searchControls.setSearchScope(_ldapConfiguration.getScope()); - searchControls.setReturningAttributes(_ldapConfiguration.getReturnAttributes()); - - String basedn = _ldapConfiguration.getBaseDn(); - if (StringUtils.isBlank(basedn)) { - throw new IllegalArgumentException("ldap basedn is not configured"); - } - byte[] cookie = null; - int pageSize = _ldapConfiguration.getLdapPageSize(); - context.setRequestControls(new Control[]{new PagedResultsControl(pageSize, Control.NONCRITICAL)}); - final List users = new ArrayList(); - NamingEnumeration results; - do { - results = context.search(basedn, generateSearchFilter(username), searchControls); - while (results.hasMoreElements()) { - final SearchResult result = results.nextElement(); - users.add(createUser(result)); - } - Control[] contextControls = context.getResponseControls(); - if (contextControls != null) { - for (Control control : contextControls) { - if (control instanceof PagedResultsResponseControl) { - PagedResultsResponseControl prrc = (PagedResultsResponseControl) control; - cookie = prrc.getCookie(); - } - } - } else { - s_logger.info("No controls were sent from the ldap server"); - } - context.setRequestControls(new Control[] {new PagedResultsControl(pageSize, cookie, Control.CRITICAL)}); - } while (cookie != null); - - return users; - } -} \ No newline at end of file + public List searchUsers(final String username, final LdapContext context) throws NamingException, IOException; +} diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapUserManagerFactory.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapUserManagerFactory.java new file mode 100644 index 00000000000..b7414c7c250 --- /dev/null +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapUserManagerFactory.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.ldap; + +import org.apache.log4j.Logger; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import java.util.HashMap; +import java.util.Map; + +public class LdapUserManagerFactory implements ApplicationContextAware { + + + public static final Logger s_logger = Logger.getLogger(LdapUserManagerFactory.class.getName()); + + private static Map ldapUserManagerMap = new HashMap<>(); + + static ApplicationContext applicationCtx; + + public LdapUserManager getInstance(LdapUserManager.Provider provider) { + LdapUserManager ldapUserManager; + if (provider == LdapUserManager.Provider.MICROSOFTAD) { + ldapUserManager = ldapUserManagerMap.get(LdapUserManager.Provider.MICROSOFTAD); + if (ldapUserManager == null) { + ldapUserManager = new ADLdapUserManagerImpl(); + applicationCtx.getAutowireCapableBeanFactory().autowireBeanProperties(ldapUserManager, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true); + ldapUserManagerMap.put(LdapUserManager.Provider.MICROSOFTAD, ldapUserManager); + } + } else { + //defaults to opendldap + ldapUserManager = ldapUserManagerMap.get(LdapUserManager.Provider.OPENLDAP); + if (ldapUserManager == null) { + ldapUserManager = new OpenLdapUserManagerImpl(); + applicationCtx.getAutowireCapableBeanFactory().autowireBeanProperties(ldapUserManager, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true); + ldapUserManagerMap.put(LdapUserManager.Provider.OPENLDAP, ldapUserManager); + } + } + return ldapUserManager; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + applicationCtx = applicationContext; + } +} diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/OpenLdapUserManagerImpl.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/OpenLdapUserManagerImpl.java new file mode 100644 index 00000000000..11e6bcfc92a --- /dev/null +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/OpenLdapUserManagerImpl.java @@ -0,0 +1,233 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.ldap; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.inject.Inject; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.SearchControls; +import javax.naming.directory.SearchResult; +import javax.naming.ldap.Control; +import javax.naming.ldap.LdapContext; +import javax.naming.ldap.PagedResultsControl; +import javax.naming.ldap.PagedResultsResponseControl; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; + +public class OpenLdapUserManagerImpl implements LdapUserManager { + private static final Logger s_logger = Logger.getLogger(OpenLdapUserManagerImpl.class.getName()); + + @Inject + protected LdapConfiguration _ldapConfiguration; + + public OpenLdapUserManagerImpl() { + } + + public OpenLdapUserManagerImpl(final LdapConfiguration ldapConfiguration) { + _ldapConfiguration = ldapConfiguration; + } + + protected LdapUser createUser(final SearchResult result) throws NamingException { + final Attributes attributes = result.getAttributes(); + + final String username = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getUsernameAttribute()); + final String email = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getEmailAttribute()); + final String firstname = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getFirstnameAttribute()); + final String lastname = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getLastnameAttribute()); + final String principal = result.getNameInNamespace(); + + String domain = principal.replace("cn=" + LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getCommonNameAttribute()) + ",", ""); + domain = domain.replace("," + _ldapConfiguration.getBaseDn(), ""); + domain = domain.replace("ou=", ""); + + return new LdapUser(username, email, firstname, lastname, principal, domain); + } + + private String generateSearchFilter(final String username) { + final StringBuilder userObjectFilter = new StringBuilder(); + userObjectFilter.append("(objectClass="); + userObjectFilter.append(_ldapConfiguration.getUserObject()); + userObjectFilter.append(")"); + + final StringBuilder usernameFilter = new StringBuilder(); + usernameFilter.append("("); + usernameFilter.append(_ldapConfiguration.getUsernameAttribute()); + usernameFilter.append("="); + usernameFilter.append((username == null ? "*" : username)); + usernameFilter.append(")"); + + final StringBuilder memberOfFilter = new StringBuilder(); + if (_ldapConfiguration.getSearchGroupPrinciple() != null) { + memberOfFilter.append("(memberof="); + memberOfFilter.append(_ldapConfiguration.getSearchGroupPrinciple()); + memberOfFilter.append(")"); + } + + final StringBuilder result = new StringBuilder(); + result.append("(&"); + result.append(userObjectFilter); + result.append(usernameFilter); + result.append(memberOfFilter); + result.append(")"); + + 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(); + } + + @Override + public LdapUser getUser(final String username, final LdapContext context) throws NamingException, IOException { + List result = searchUsers(username, context); + if (result!= null && result.size() == 1) { + return result.get(0); + } else { + throw new NamingException("No user found for username " + username); + } + } + + @Override + public List getUsers(final LdapContext context) throws NamingException, IOException { + return getUsers(null, context); + } + + @Override + public List getUsers(final String username, final LdapContext context) throws NamingException, IOException { + List users = searchUsers(username, context); + + if (CollectionUtils.isNotEmpty(users)) { + Collections.sort(users); + } + return users; + } + + @Override + public List getUsersInGroup(String groupName, LdapContext context) throws NamingException { + String attributeName = _ldapConfiguration.getGroupUniqueMemeberAttribute(); + final SearchControls controls = new SearchControls(); + controls.setSearchScope(_ldapConfiguration.getScope()); + controls.setReturningAttributes(new String[] {attributeName}); + + NamingEnumeration result = context.search(_ldapConfiguration.getBaseDn(), generateGroupSearchFilter(groupName), controls); + + final List users = new ArrayList(); + //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()); + try{ + users.add(getUserForDn(userdn, context)); + } catch (NamingException e){ + s_logger.info("Userdn: " + userdn + " Not Found:: Exception message: " + e.getMessage()); + } + } + } + + Collections.sort(users); + + return users; + } + + private LdapUser getUserForDn(String userdn, LdapContext context) throws NamingException { + final SearchControls controls = new SearchControls(); + controls.setSearchScope(_ldapConfiguration.getScope()); + controls.setReturningAttributes(_ldapConfiguration.getReturnAttributes()); + + NamingEnumeration 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); + } + } + + @Override + public List searchUsers(final LdapContext context) throws NamingException, IOException { + return searchUsers(null, context); + } + + @Override + public List searchUsers(final String username, final LdapContext context) throws NamingException, IOException { + + final SearchControls searchControls = new SearchControls(); + + searchControls.setSearchScope(_ldapConfiguration.getScope()); + searchControls.setReturningAttributes(_ldapConfiguration.getReturnAttributes()); + + String basedn = _ldapConfiguration.getBaseDn(); + if (StringUtils.isBlank(basedn)) { + throw new IllegalArgumentException("ldap basedn is not configured"); + } + byte[] cookie = null; + int pageSize = _ldapConfiguration.getLdapPageSize(); + context.setRequestControls(new Control[]{new PagedResultsControl(pageSize, Control.NONCRITICAL)}); + final List users = new ArrayList(); + NamingEnumeration results; + do { + results = context.search(basedn, generateSearchFilter(username), searchControls); + while (results.hasMoreElements()) { + final SearchResult result = results.nextElement(); + users.add(createUser(result)); + } + Control[] contextControls = context.getResponseControls(); + if (contextControls != null) { + for (Control control : contextControls) { + if (control instanceof PagedResultsResponseControl) { + PagedResultsResponseControl prrc = (PagedResultsResponseControl) control; + cookie = prrc.getCookie(); + } + } + } else { + s_logger.info("No controls were sent from the ldap server"); + } + context.setRequestControls(new Control[] {new PagedResultsControl(pageSize, cookie, Control.CRITICAL)}); + } while (cookie != null); + + return users; + } +} \ No newline at end of file diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/ADLdapUserManagerImplSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/ADLdapUserManagerImplSpec.groovy new file mode 100644 index 00000000000..6fafa3edf22 --- /dev/null +++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/ADLdapUserManagerImplSpec.groovy @@ -0,0 +1,70 @@ +/* + * 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 groovy.org.apache.cloudstack.ldap + +import org.apache.cloudstack.ldap.ADLdapUserManagerImpl +import org.apache.cloudstack.ldap.LdapConfiguration +import spock.lang.Shared + +import javax.naming.directory.SearchControls +import javax.naming.ldap.LdapContext + +class ADLdapUserManagerImplSpec extends spock.lang.Specification { + + @Shared + ADLdapUserManagerImpl adLdapUserManager; + + @Shared + LdapConfiguration ldapConfiguration; + + def setup() { + adLdapUserManager = new ADLdapUserManagerImpl(); + ldapConfiguration = Mock(LdapConfiguration); + adLdapUserManager._ldapConfiguration = ldapConfiguration; + } + + def "test generate AD search filter"() { + ldapConfiguration.getUserObject() >> "user" + ldapConfiguration.getCommonNameAttribute() >> "CN" + ldapConfiguration.getBaseDn() >> "DC=cloud,DC=citrix,DC=com" + + def result = adLdapUserManager.generateADGroupSearchFilter(group); + expect: + assert result.contains("memberOf:1.2.840.113556.1.4.1941:=") + result == "(&(objectClass=user)(memberOf:1.2.840.113556.1.4.1941:=CN=" + group + ",DC=cloud,DC=citrix,DC=com))" + where: + group << ["dev", "dev-hyd"] + } + + def "test getUsersInGroup null group"() { + ldapConfiguration.getScope() >> SearchControls.SUBTREE_SCOPE + ldapConfiguration.getReturnAttributes() >> ["username", "firstname", "lastname", "email"] + ldapConfiguration.getBaseDn() >>> [null, null, "DC=cloud,DC=citrix,DC=com"] + + LdapContext context = Mock(LdapContext); + + when: + def result = adLdapUserManager.getUsersInGroup(group, context) + then: + thrown(IllegalArgumentException) + where: + group << [null, "group", null] + + } +} diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapConfigurationSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapConfigurationSpec.groovy index adc3463afde..4f93adff435 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 @@ -25,6 +25,8 @@ import org.apache.cloudstack.framework.config.impl.ConfigurationVO import org.apache.cloudstack.ldap.LdapConfiguration import org.apache.cloudstack.ldap.LdapConfigurationVO import org.apache.cloudstack.ldap.LdapManager +import org.apache.cloudstack.ldap.LdapUserManager +import org.apache.cloudstack.ldap.dao.LdapConfigurationDao import org.apache.cxf.common.util.StringUtils import javax.naming.directory.SearchControls @@ -33,8 +35,8 @@ class LdapConfigurationSpec extends spock.lang.Specification { def "Test that getAuthentication returns none"() { given: "We have a ConfigDao, LdapManager and LdapConfiguration" def configDao = Mock(ConfigurationDao) - def ldapManager = Mock(LdapManager) - def ldapConfiguration = new LdapConfiguration(configDao, ldapManager) + def ldapConfigurationDao = Mock(LdapConfigurationDao) + def ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) when: "Get authentication is called" String authentication = ldapConfiguration.getAuthentication() then: "none should be returned" @@ -44,8 +46,8 @@ class LdapConfigurationSpec extends spock.lang.Specification { def "Test that getAuthentication returns simple"() { given: "We have a configDao, LdapManager and LdapConfiguration with bind principle and password set" def configDao = Mock(ConfigurationDao) - def ldapManager = Mock(LdapManager) - def ldapConfiguration = new LdapConfiguration(configDao, ldapManager) + def ldapConfigurationDao = Mock(LdapConfigurationDao) + def ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) configDao.getValue("ldap.bind.password") >> "password" configDao.getValue("ldap.bind.principal") >> "cn=rmurphy,dc=cloudstack,dc=org" when: "Get authentication is called" @@ -58,8 +60,8 @@ class LdapConfigurationSpec extends spock.lang.Specification { given: "We have a ConfigDao, LdapManager and ldapConfiguration with a baseDn value set." def configDao = Mock(ConfigurationDao) configDao.getValue("ldap.basedn") >> "dc=cloudstack,dc=org" - def ldapManager = Mock(LdapManager) - def ldapConfiguration = new LdapConfiguration(configDao, ldapManager) + def ldapConfigurationDao = Mock(LdapConfigurationDao) + def ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) when: "Get basedn is called" String baseDn = ldapConfiguration.getBaseDn(); then: "The set baseDn should be returned" @@ -70,8 +72,8 @@ class LdapConfigurationSpec extends spock.lang.Specification { given: "Given that we have a ConfigDao, LdapManager and LdapConfiguration" def configDao = Mock(ConfigurationDao) configDao.getValue("ldap.email.attribute") >> "mail" - def ldapManager = Mock(LdapManager) - def ldapConfiguration = new LdapConfiguration(configDao, ldapManager) + def ldapConfigurationDao = Mock(LdapConfigurationDao) + def ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) when: "Get Email Attribute is called" String emailAttribute = ldapConfiguration.getEmailAttribute() then: "mail should be returned" @@ -81,8 +83,8 @@ class LdapConfigurationSpec extends spock.lang.Specification { def "Test that getFactory returns com.sun.jndi.ldap.LdapCtxFactory"() { given: "We have a ConfigDao, LdapManager and LdapConfiguration" def configDao = Mock(ConfigurationDao) - def ldapManager = Mock(LdapManager) - def ldapConfiguration = new LdapConfiguration(configDao, ldapManager) + def ldapConfigurationDao = Mock(LdapConfigurationDao) + def ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) when: "Get Factory is scalled" String factory = ldapConfiguration.getFactory(); then: "com.sun.jndi.ldap.LdapCtxFactory is returned" @@ -93,8 +95,8 @@ class LdapConfigurationSpec extends spock.lang.Specification { given: "We have a ConfigDao, LdapManager and LdapConfiguration" def configDao = Mock(ConfigurationDao) configDao.getValue("ldap.firstname.attribute") >> "givenname" - def ldapManager = Mock(LdapManager) - def ldapConfiguration = new LdapConfiguration(configDao, ldapManager) + def ldapConfigurationDao = Mock(LdapConfigurationDao) + def ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) when: "Get firstname attribute is called" String firstname = ldapConfiguration.getFirstnameAttribute() then: "givennam should be returned" @@ -105,8 +107,8 @@ class LdapConfigurationSpec extends spock.lang.Specification { given: "We have a ConfigDao, LdapManager and LdapConfiguration" def configDao = Mock(ConfigurationDao) configDao.getValue("ldap.lastname.attribute") >> "sn" - def ldapManager = Mock(LdapManager) - def ldapConfiguration = new LdapConfiguration(configDao, ldapManager) + def ldapConfigurationDao = Mock(LdapConfigurationDao) + def ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) when: "Get Lastname Attribute is scalled " String lastname = ldapConfiguration.getLastnameAttribute() then: "sn should be returned" @@ -120,8 +122,8 @@ class LdapConfigurationSpec extends spock.lang.Specification { configDao.getValue("ldap.lastname.attribute") >> "sn" configDao.getValue("ldap.username.attribute") >> "uid" configDao.getValue("ldap.email.attribute") >> "mail" - def ldapManager = Mock(LdapManager) - def ldapConfiguration = new LdapConfiguration(configDao, ldapManager) + def ldapConfigurationDao = Mock(LdapConfigurationDao) + def ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) when: "Get return attributes is called" String[] returnAttributes = ldapConfiguration.getReturnAttributes() then: "An array containing uid, mail, givenname, sn and cn is returned" @@ -131,8 +133,8 @@ class LdapConfigurationSpec extends spock.lang.Specification { def "Test that getScope returns SearchControls.SUBTREE_SCOPE"() { given: "We have ConfigDao, LdapManager and LdapConfiguration" def configDao = Mock(ConfigurationDao) - def ldapManager = Mock(LdapManager) - def ldapConfiguration = new LdapConfiguration(configDao, ldapManager) + def ldapConfigurationDao = Mock(LdapConfigurationDao) + def ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) when: "Get scope is called" int scope = ldapConfiguration.getScope() then: "SearchControls.SUBTRE_SCOPE should be returned" @@ -143,8 +145,8 @@ class LdapConfigurationSpec extends spock.lang.Specification { given: "We have ConfigDao, LdapManager and LdapConfiguration" def configDao = Mock(ConfigurationDao) configDao.getValue("ldap.username.attribute") >> "uid" - def ldapManager = Mock(LdapManager) - def ldapConfiguration = new LdapConfiguration(configDao, ldapManager) + def ldapConfigurationDao = Mock(LdapConfigurationDao) + def ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) when: "Get Username Attribute is called" String usernameAttribute = ldapConfiguration.getUsernameAttribute() then: "uid should be returned" @@ -155,8 +157,8 @@ class LdapConfigurationSpec extends spock.lang.Specification { given: "We have a ConfigDao, LdapManager and LdapConfiguration" def configDao = Mock(ConfigurationDao) configDao.getValue("ldap.user.object") >> "inetOrgPerson" - def ldapManager = Mock(LdapManager) - def ldapConfiguration = new LdapConfiguration(configDao, ldapManager) + def ldapConfigurationDao = Mock(LdapConfigurationDao) + def ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) when: "Get user object is called" String userObject = ldapConfiguration.getUserObject() then: "inetOrgPerson is returned" @@ -166,14 +168,14 @@ class LdapConfigurationSpec extends spock.lang.Specification { def "Test that providerUrl successfully returns a URL when a configuration is available"() { given: "We have a ConfigDao, LdapManager, LdapConfiguration" def configDao = Mock(ConfigurationDao) - def ldapManager = Mock(LdapManager) + def ldapConfigurationDao = Mock(LdapConfigurationDao) List ldapConfigurationList = new ArrayList() ldapConfigurationList.add(new LdapConfigurationVO("localhost", 389)) Pair, Integer> result = new Pair, Integer>(); result.set(ldapConfigurationList, ldapConfigurationList.size()) - ldapManager.listConfigurations(_) >> result + ldapConfigurationDao.searchConfigurations(_,_) >> result - LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapManager) + LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) when: "A request is made to get the providerUrl" String providerUrl = ldapConfiguration.getProviderUrl() @@ -186,8 +188,8 @@ class LdapConfigurationSpec extends spock.lang.Specification { given: "We have a ConfigDao with a value for ldap.search.group.principle and an LdapConfiguration" def configDao = Mock(ConfigurationDao) configDao.getValue("ldap.search.group.principle") >> "cn=cloudstack,cn=users,dc=cloudstack,dc=org" - def ldapManager = Mock(LdapManager) - LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapManager) + def ldapConfigurationDao = Mock(LdapConfigurationDao) + LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) when: "A request is made to get the search group principle" String result = ldapConfiguration.getSearchGroupPrinciple(); @@ -200,8 +202,8 @@ class LdapConfigurationSpec extends spock.lang.Specification { given: "We have a ConfigDao with a value for truststore password" def configDao = Mock(ConfigurationDao) configDao.getValue("ldap.truststore.password") >> "password" - def ldapManager = Mock(LdapManager) - LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapManager) + def ldapConfigurationDao = Mock(LdapConfigurationDao) + LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) when: "A request is made to get the truststore password" String result = ldapConfiguration.getTrustStorePassword() @@ -215,8 +217,8 @@ class LdapConfigurationSpec extends spock.lang.Specification { def configDao = Mock(ConfigurationDao) configDao.getValue("ldap.truststore") >> "/tmp/ldap.ts" configDao.getValue("ldap.truststore.password") >> "password" - def ldapManager = Mock(LdapManager) - LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapManager) + def ldapConfigurationDao = Mock(LdapConfigurationDao) + LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) when: "A request is made to get the status of SSL" boolean result = ldapConfiguration.getSSLStatus(); @@ -230,8 +232,8 @@ class LdapConfigurationSpec extends spock.lang.Specification { def configDao = Mock(ConfigurationDao) configDao.getValue("ldap.group.object") >> groupObject - def ldapManger = Mock(LdapManager) - LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapManger) + def ldapConfigurationDao = Mock(LdapConfigurationDao) + LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) def expectedResult = groupObject == null ? "groupOfUniqueNames" : groupObject def result = ldapConfiguration.getGroupObject() @@ -246,8 +248,8 @@ class LdapConfigurationSpec extends spock.lang.Specification { def configDao = Mock(ConfigurationDao) configDao.getValue("ldap.group.user.uniquemember") >> groupObject - def ldapManger = Mock(LdapManager) - LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapManger) + def ldapConfigurationDao = Mock(LdapConfigurationDao) + LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) def expectedResult = groupObject == null ? "uniquemember" : groupObject def result = ldapConfiguration.getGroupUniqueMemeberAttribute() @@ -268,8 +270,8 @@ class LdapConfigurationSpec extends spock.lang.Specification { configDepotImpl.global() >> configDao ConfigKey.init(configDepotImpl) - def ldapManger = Mock(LdapManager) - LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapManger) + def ldapConfigurationDao = Mock(LdapConfigurationDao) + LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) def expected = timeout == null ? 1000 : timeout.toLong() //1000 is the default value @@ -280,4 +282,28 @@ class LdapConfigurationSpec extends spock.lang.Specification { timeout << ["1000000", "1000", null] } + def "Test getLdapProvider()"() { + given: "We have configdao for ldap group object" + def configDao = Mock(ConfigurationDao) + ConfigurationVO configurationVo = new ConfigurationVO("ldap.read.timeout", LdapConfiguration.ldapProvider); + configurationVo.setValue(provider) + configDao.findById("ldap.provider") >> configurationVo + + def configDepotImpl = Mock(ConfigDepotImpl) + configDepotImpl.global() >> configDao + ConfigKey.init(configDepotImpl) + + def ldapConfigurationDao = Mock(LdapConfigurationDao) + LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao) + + def expected = provider.equalsIgnoreCase("microsoftad") ? LdapUserManager.Provider.MICROSOFTAD : LdapUserManager.Provider.OPENLDAP //"openldap" is the default value + + def result = ldapConfiguration.getLdapProvider() + expect: + println "asserting for provider configuration: " + provider + result == expected + where: + provider << ["openldap", "microsoftad", "", " ", "xyz", "MicrosoftAd", "OpenLdap", "MicrosoftAD"] + } + } 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 c57cc7872df..1f17e704f52 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 @@ -57,7 +57,7 @@ class LdapCreateAccountCmdSpec extends spock.lang.Specification { AccountService accountService = Mock(AccountService) def ldapCreateAccountCmd = Spy(LdapCreateAccountCmd, constructorArgs: [ldapManager, accountService]) ldapCreateAccountCmd.getCurrentContext() >> Mock(CallContext) - ldapCreateAccountCmd.createCloudstackUserAccount(_) >> null + ldapCreateAccountCmd.createCloudstackUserAccount(_, _, _) >> null when: "Cloudstack fail to create the user" ldapCreateAccountCmd.execute() then: "An exception is thrown" 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 ee317206854..4c62a4eb67e 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 @@ -41,8 +41,11 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + def ldapConfiguration = Mock(LdapConfiguration) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager ldapContextFactory.createBindContext() >> { throw new NoLdapUserMatchingQueryException() } - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "We search for a user but there is a bind issue" ldapManager.getUser("rmurphy") then: "an exception is thrown" @@ -54,8 +57,11 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + def ldapConfiguration = Mock(LdapConfiguration) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager ldapContextFactory.createBindContext() >> { throw new NamingException() } - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "We search for a group of users but there is a bind issue" ldapManager.getUsers() then: "An exception is thrown" @@ -67,8 +73,11 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + def ldapConfiguration = Mock(LdapConfiguration) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager ldapContextFactory.createBindContext() >> { throw new NamingException() } - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "We search for users" ldapManager.searchUsers("rmurphy") then: "An exception is thrown" @@ -80,7 +89,10 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + def ldapConfiguration = Mock(LdapConfiguration) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "A ldap configuration response is generated" def result = ldapManager.createLdapConfigurationResponse(new LdapConfigurationVO("localhost", 389)) then: "the result of the response should match the given LdapConfigurationVO" @@ -93,7 +105,10 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + def ldapConfiguration = Mock(LdapConfiguration) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "A ldap user response is generated" def result = ldapManager.createLdapUserResponse(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")) @@ -111,11 +126,14 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + def ldapConfiguration = Mock(LdapConfiguration) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager ldapContextFactory.createBindContext() >> null List users = new ArrayList<>(); users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null)) ldapUserManager.getUsers(_) >> users; - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "We search for a group of users" def result = ldapManager.getUsers() then: "A list greater than 0 is returned" @@ -127,9 +145,12 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + def ldapConfiguration = Mock(LdapConfiguration) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager ldapContextFactory.createBindContext() >> null ldapUserManager.getUser(_, _) >> new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null) - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "We search for a user" def result = ldapManager.getUser("rmurphy") then: "The user is returned" @@ -145,7 +166,10 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + def ldapConfiguration = Mock(LdapConfiguration) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "The context is closed" def context = Mock(InitialLdapContext) ldapManager.closeContext(context) @@ -159,7 +183,10 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapContextFactory = Mock(LdapContextFactory) ldapContextFactory.createUserContext(_, _) >> { throw new NamingException() } def ldapUserManager = Mock(LdapUserManager) - def ldapManager = Spy(LdapManagerImpl, constructorArgs: [ldapConfigurationDao, ldapContextFactory, ldapUserManager]) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager + def ldapConfiguration = Mock(LdapConfiguration) + def ldapManager = Spy(LdapManagerImpl, constructorArgs: [ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration]) ldapManager.getUser(_) >> { new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null) } when: "The user attempts to authenticate with a bad password" def result = ldapManager.canAuthenticate("rmurphy", "password") @@ -172,7 +199,10 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) - def ldapManager = Spy(LdapManagerImpl, constructorArgs: [ldapConfigurationDao, ldapContextFactory, ldapUserManager]) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager + def ldapConfiguration = Mock(LdapConfiguration) + def ldapManager = Spy(LdapManagerImpl, constructorArgs: [ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration]) ldapManager.getUser(_) >> { throw new NamingException() } when: "The user attempts to authenticate and the user is not found" def result = ldapManager.canAuthenticate("rmurphy", "password") @@ -185,8 +215,11 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + def ldapConfiguration = Mock(LdapConfiguration) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager ldapConfigurationDao.findByHostname(_) >> null - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "A ldap configuration that doesn't exist is deleted" ldapManager.deleteConfiguration("localhost") then: "A exception is thrown" @@ -198,7 +231,10 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + def ldapConfiguration = Mock(LdapConfiguration) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "The context is closed" def context = Mock(InitialLdapContext) context.close() >> { throw new NamingException() } @@ -213,7 +249,10 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapContextFactory = Mock(LdapContextFactory) ldapContextFactory.createUserContext(_, _) >> null def ldapUserManager = Mock(LdapUserManager) - def ldapManager = Spy(LdapManagerImpl, constructorArgs: [ldapConfigurationDao, ldapContextFactory, ldapUserManager]) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + def ldapConfiguration = Mock(LdapConfiguration) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager + def ldapManager = Spy(LdapManagerImpl, constructorArgs: [ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration]) ldapManager.getUser(_) >> { new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null) } when: "A user authenticates" def result = ldapManager.canAuthenticate("rmurphy", "password") @@ -226,13 +265,16 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager + def ldapConfiguration = Mock(LdapConfiguration) ldapConfigurationDao.findByHostname(_) >> { def configuration = new LdapConfigurationVO("localhost", 389) configuration.setId(0); return configuration; } ldapConfigurationDao.remove(_) >> null - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "A ldap configuration is deleted" def result = ldapManager.deleteConfiguration("localhost") then: "The deleted configuration is returned" @@ -245,13 +287,16 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager + def ldapConfiguration = Mock(LdapConfiguration) ldapContextFactory.createBindContext() >> null; List users = new ArrayList(); users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")) ldapUserManager.getUsers(_, _) >> users; - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "We search for users" def result = ldapManager.searchUsers("rmurphy"); then: "A list of atleast 1 is returned" @@ -263,9 +308,12 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + def ldapConfiguration = Mock(LdapConfiguration) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager ldapContextFactory.createBindContext(_) >> null ldapConfigurationDao.persist(_) >> null - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "A ldap configuration is added" def result = ldapManager.addConfiguration("localhost", 389) then: "the resulting object contain the given hostname and port" @@ -278,8 +326,11 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + def ldapConfiguration = Mock(LdapConfiguration) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager ldapContextFactory.createBindContext(_) >> { throw new NamingException() } - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "A configuration is added that can not be binded" ldapManager.addConfiguration("localhost", 389) then: "An exception is thrown" @@ -291,8 +342,11 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + def ldapConfiguration = Mock(LdapConfiguration) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager ldapConfigurationDao.findByHostname(_) >> new LdapConfigurationVO("localhost", 389) - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "a configuration that already exists is added" ldapManager.addConfiguration("localhost", 389) then: "An exception is thrown" @@ -318,8 +372,11 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager + def ldapConfiguration = Mock(LdapConfiguration) final List> cmdList = supportedLdapCommands() - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "Get commands is called" def result = ldapManager.getCommands() then: "it must return all the commands" @@ -332,12 +389,15 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + def ldapConfiguration = Mock(LdapConfiguration) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager List ldapConfigurationList = new ArrayList() ldapConfigurationList.add(new LdapConfigurationVO("localhost", 389)) Pair, Integer> configurations = new Pair, Integer>(); configurations.set(ldapConfigurationList, ldapConfigurationList.size()) ldapConfigurationDao.searchConfigurations(_, _) >> configurations - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "A request for configurations is made" def result = ldapManager.listConfigurations(new LdapListConfigurationCmd()) then: "Then atleast 1 ldap configuration is returned" @@ -349,12 +409,15 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + def ldapConfiguration = Mock(LdapConfiguration) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager List ldapConfigurationList = new ArrayList() ldapConfigurationList.add(new LdapConfigurationVO("localhost", 389)) Pair, Integer> configurations = new Pair, Integer>(); configurations.set(ldapConfigurationList, ldapConfigurationList.size()) ldapConfigurationDao.searchConfigurations(_, _) >> configurations - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "A request to find out is ldap enabled" def result = ldapManager.isLdapEnabled(); then: "true is returned because a configuration was found" @@ -366,11 +429,14 @@ class LdapManagerImplSpec extends spock.lang.Specification { def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl) def ldapContextFactory = Mock(LdapContextFactory) def ldapUserManager = Mock(LdapUserManager) + def ldapUserManagerFactory = Mock(LdapUserManagerFactory) + def ldapConfiguration = Mock(LdapConfiguration) + ldapUserManagerFactory.getInstance(_) >> ldapUserManager ldapContextFactory.createBindContext() >> null List users = new ArrayList<>(); users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", "engineering")) ldapUserManager.getUsersInGroup("engineering", _) >> users; - def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager) + def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) when: "We search for a group of users" def result = ldapManager.getUsersInGroup("engineering") then: "A list greater of size one is returned" diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapUserManagerFactorySpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapUserManagerFactorySpec.groovy new file mode 100644 index 00000000000..ca423d3e630 --- /dev/null +++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapUserManagerFactorySpec.groovy @@ -0,0 +1,57 @@ +/* + * 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 groovy.org.apache.cloudstack.ldap + +import org.apache.cloudstack.ldap.ADLdapUserManagerImpl +import org.apache.cloudstack.ldap.LdapUserManager +import org.apache.cloudstack.ldap.LdapUserManagerFactory +import org.apache.cloudstack.ldap.OpenLdapUserManagerImpl +import org.springframework.beans.factory.config.AutowireCapableBeanFactory +import org.springframework.context.ApplicationContext +import spock.lang.Shared + +class LdapUserManagerFactorySpec extends spock.lang.Specification { + + @Shared + def LdapUserManagerFactory ldapUserManagerFactory; + + def setupSpec() { + ldapUserManagerFactory = new LdapUserManagerFactory(); + ApplicationContext applicationContext = Mock(ApplicationContext); + AutowireCapableBeanFactory autowireCapableBeanFactory = Mock(AutowireCapableBeanFactory); + applicationContext.getAutowireCapableBeanFactory() >> autowireCapableBeanFactory; + ldapUserManagerFactory.setApplicationContext(applicationContext); + } + + def "Test getInstance() from factory"() { + def result = ldapUserManagerFactory.getInstance(id); + + def expected; + if(id == LdapUserManager.Provider.MICROSOFTAD) { + expected = ADLdapUserManagerImpl.class; + } else { + expected = OpenLdapUserManagerImpl.class; + } + + expect: + assert result.class.is(expected) + where: + id << [LdapUserManager.Provider.MICROSOFTAD, LdapUserManager.Provider.OPENLDAP, null] + } +} 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/OpenLdapUserManagerSpec.groovy similarity index 92% rename from plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapUserManagerSpec.groovy rename to plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/OpenLdapUserManagerSpec.groovy index d1f3667b8c6..cb08c8fd47c 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/OpenLdapUserManagerSpec.groovy @@ -18,6 +18,7 @@ package groovy.org.apache.cloudstack.ldap import org.apache.cloudstack.ldap.LdapConfiguration import org.apache.cloudstack.ldap.LdapUserManager +import org.apache.cloudstack.ldap.OpenLdapUserManagerImpl import spock.lang.Shared import javax.naming.NamingException @@ -29,7 +30,7 @@ import javax.naming.directory.SearchResult import javax.naming.ldap.InitialLdapContext import javax.naming.ldap.LdapContext -class LdapUserManagerSpec extends spock.lang.Specification { +class OpenLdapUserManagerSpec extends spock.lang.Specification { @Shared private def ldapConfiguration @@ -184,7 +185,7 @@ class LdapUserManagerSpec extends spock.lang.Specification { given: "We have attributes, a search and a user manager" def attributes = createUserAttributes(username, email, firstname, lastname) def search = createSearchResult(attributes) - def userManager = new LdapUserManager(ldapConfiguration) + def userManager = new OpenLdapUserManagerImpl(ldapConfiguration) def result = userManager.createUser(search) expect: "The crated user the data supplied from LDAP" @@ -199,7 +200,7 @@ class LdapUserManagerSpec extends spock.lang.Specification { def "Test successfully returning a list from get users"() { given: "We have a LdapUserManager" - def userManager = new LdapUserManager(ldapConfiguration) + def userManager = new OpenLdapUserManagerImpl(ldapConfiguration) when: "A request for users is made" def result = userManager.getUsers(username, createContext()) @@ -211,7 +212,7 @@ class LdapUserManagerSpec extends spock.lang.Specification { def "Test successfully returning a list from get users when no username is given"() { given: "We have a LdapUserManager" - def userManager = new LdapUserManager(ldapConfiguration) + def userManager = new OpenLdapUserManagerImpl(ldapConfiguration) when: "Get users is called without a username" def result = userManager.getUsers(createContext()) @@ -222,7 +223,7 @@ class LdapUserManagerSpec extends spock.lang.Specification { def "Test successfully returning a ldap user from searchUsers"() { given: "We have a LdapUserManager" - def userManager = new LdapUserManager(ldapConfiguration) + def userManager = new OpenLdapUserManagerImpl(ldapConfiguration) when: "We search for users" def result = userManager.searchUsers(createContext()) @@ -234,7 +235,7 @@ class LdapUserManagerSpec extends spock.lang.Specification { def "Test successfully returning an Ldap user from a get user request"() { given: "We have a LdapUserMaanger" - def userManager = new LdapUserManager(ldapConfiguration) + def userManager = new OpenLdapUserManagerImpl(ldapConfiguration) when: "A request for a user is made" def result = userManager.getUser(username, createContext()) @@ -255,7 +256,7 @@ class LdapUserManagerSpec extends spock.lang.Specification { def context = Mock(LdapContext) context.search(_, _, _) >> searchUsersResults; - def userManager = new LdapUserManager(ldapConfiguration) + def userManager = new OpenLdapUserManagerImpl(ldapConfiguration) when: "a get user request is made and no user is found" def result = userManager.getUser(username, context) @@ -266,14 +267,14 @@ class LdapUserManagerSpec extends spock.lang.Specification { def "Test that a newly created Ldap User Manager is not null"() { given: "You have created a new Ldap user manager object" - def result = new LdapUserManager(); + def result = new OpenLdapUserManagerImpl(); 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 ldapUserManager = new OpenLdapUserManagerImpl(ldapConfiguration) def groupName = varGroupName == null ? "*" : varGroupName def expectedResult = "(&(objectClass=groupOfUniqueNames)(cn=" + groupName + "))"; @@ -286,7 +287,7 @@ class LdapUserManagerSpec extends spock.lang.Specification { def "test successful getUsersInGroup one user"() { given: "ldap user manager and ldap config" - def ldapUserManager = new LdapUserManager(ldapConfiguration) + def ldapUserManager = new OpenLdapUserManagerImpl(ldapConfiguration) when: "A request for users is made" def result = ldapUserManager.getUsersInGroup("engineering", createGroupSearchContextOneUser()) @@ -296,7 +297,7 @@ class LdapUserManagerSpec extends spock.lang.Specification { def "test successful getUsersInGroup no user"() { given: "ldap user manager and ldap config" - def ldapUserManager = new LdapUserManager(ldapConfiguration) + def ldapUserManager = new OpenLdapUserManagerImpl(ldapConfiguration) when: "A request for users is made" def result = ldapUserManager.getUsersInGroup("engineering", createGroupSearchContextNoUser()) @@ -306,7 +307,7 @@ class LdapUserManagerSpec extends spock.lang.Specification { def "test successful getUserForDn"() { given: "ldap user manager and ldap config" - def ldapUserManager = new LdapUserManager(ldapConfiguration) + def ldapUserManager = new OpenLdapUserManagerImpl(ldapConfiguration) when: "A request for users is made" def result = ldapUserManager.getUserForDn("cn=Ryan Murphy,ou=engineering,dc=cloudstack,dc=org", createContext()) @@ -324,7 +325,7 @@ class LdapUserManagerSpec extends spock.lang.Specification { given: "ldap configuration where basedn is not set" def ldapconfig = Mock(LdapConfiguration) ldapconfig.getBaseDn() >> null - def ldapUserManager = new LdapUserManager(ldapconfig) + def ldapUserManager = new OpenLdapUserManagerImpl(ldapconfig) when: "A request for search users is made" def result = ldapUserManager.searchUsers(new InitialLdapContext())