CLOUDSTACK-10117: Account ldap binding (#2381)

Map an ldap group to an account. Ldap related settings on a domain level.
This commit is contained in:
dahn 2018-01-06 18:28:28 +01:00 committed by Rohit Yadav
parent 1d0f2128f6
commit 45df928e04
69 changed files with 2213 additions and 652 deletions

View File

@ -19,6 +19,7 @@ package org.apache.cloudstack.api.command.admin.config;
import java.util.ArrayList;
import java.util.List;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
@ -77,6 +78,12 @@ public class ListCfgsByCmd extends BaseListCmd {
description = "the ID of the Account to update the parameter value for corresponding account")
private Long accountId;
@Parameter(name = ApiConstants.DOMAIN_ID,
type = CommandType.UUID,
entityType = DomainResponse.class,
description = "the ID of the Domain to update the parameter value for corresponding domain")
private Long domainId;
@Parameter(name = ApiConstants.IMAGE_STORE_UUID,
type = CommandType.UUID,
entityType = ImageStoreResponse.class,
@ -111,6 +118,10 @@ public class ListCfgsByCmd extends BaseListCmd {
return accountId;
}
public Long getDomainId() {
return domainId;
}
public Long getImageStoreId() {
return imageStoreId;
}
@ -158,6 +169,9 @@ public class ListCfgsByCmd extends BaseListCmd {
if (getAccountId() != null) {
cfgResponse.setScope("account");
}
if (getDomainId() != null) {
cfgResponse.setScope("domain");
}
if (getImageStoreId() != null){
cfgResponse.setScope("imagestore");
}

View File

@ -18,6 +18,7 @@ package org.apache.cloudstack.api.command.admin.config;
import com.google.common.base.Strings;
import org.apache.cloudstack.acl.RoleService;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiArgValidator;
@ -76,6 +77,12 @@ public class UpdateCfgCmd extends BaseCmd {
description = "the ID of the Account to update the parameter value for corresponding account")
private Long accountId;
@Parameter(name = ApiConstants.DOMAIN_ID,
type = CommandType.UUID,
entityType = DomainResponse.class,
description = "the ID of the Domain to update the parameter value for corresponding domain")
private Long domainId;
@Parameter(name = ApiConstants.IMAGE_STORE_UUID,
type = CommandType.UUID,
entityType = ImageStoreResponse.class,
@ -115,6 +122,10 @@ public class UpdateCfgCmd extends BaseCmd {
return accountId;
}
public Long getDomainId() {
return domainId;
}
public Long getImageStoreId() {
return imageStoreId;
}
@ -157,6 +168,9 @@ public class UpdateCfgCmd extends BaseCmd {
if (getAccountId() != null) {
response.setScope("account");
}
if (getDomainId() != null) {
response.setScope("domain");
}
response.setValue(value);
this.setResponseObject(response);
} else {

View File

@ -147,6 +147,7 @@
<bean id="engineDcDetailsDaoImpl" class="org.apache.cloudstack.engine.datacenter.entity.api.db.dao.DcDetailsDaoImpl" />
<bean id="diskOfferingJoinDaoImpl" class="com.cloud.api.query.dao.DiskOfferingJoinDaoImpl" />
<bean id="domainDaoImpl" class="com.cloud.domain.dao.DomainDaoImpl" />
<bean id="domainDetailsDaoImpl" class="com.cloud.domain.dao.DomainDetailsDaoImpl" />
<bean id="domainJoinDaoImpl" class="com.cloud.api.query.dao.DomainJoinDaoImpl" />
<bean id="domainRouterDaoImpl" class="com.cloud.vm.dao.DomainRouterDaoImpl" />
<bean id="domainRouterJoinDaoImpl" class="com.cloud.api.query.dao.DomainRouterJoinDaoImpl" />

View File

@ -451,7 +451,7 @@ CREATE VIEW `cloud`.`volume_view` AS
`cloud`.`domain` resource_tag_domain ON resource_tag_domain.id = resource_tags.domain_id;
-- Extra Dhcp Options
CREATE TABLE `cloud`.`nic_extra_dhcp_options` (
CREATE TABLE IF NOT EXISTS `cloud`.`nic_extra_dhcp_options` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`uuid` varchar(255) UNIQUE,
`nic_id` bigint unsigned NOT NULL COMMENT ' nic id where dhcp options are applied',
@ -523,3 +523,20 @@ ADD COLUMN `forsystemvms` TINYINT(1) NOT NULL DEFAULT '0' COMMENT 'Indicates if
ALTER TABLE `cloud`.`op_dc_ip_address_alloc`
ADD COLUMN `vlan` INT(10) UNSIGNED NULL COMMENT 'Vlan the management network range is on';
-- ldap binding on domain level
CREATE TABLE IF NOT EXISTS `cloud`.`domain_details` (
`id` bigint unsigned NOT NULL auto_increment,
`domain_id` bigint unsigned NOT NULL COMMENT 'account id',
`name` varchar(255) NOT NULL,
`value` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `fk_domain_details__domain_id` FOREIGN KEY (`domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE cloud.ldap_configuration ADD COLUMN domain_id BIGINT(20) DEFAULT NULL;
ALTER TABLE cloud.ldap_trust_map ADD COLUMN account_id BIGINT(20) DEFAULT 0;
ALTER TABLE cloud.ldap_trust_map DROP FOREIGN KEY fk_ldap_trust_map__domain_id;
DROP INDEX uk_ldap_trust_map__domain_id ON cloud.ldap_trust_map;
CREATE UNIQUE INDEX uk_ldap_trust_map__bind_location ON ldap_trust_map (domain_id, account_id);

View File

@ -0,0 +1,76 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import com.cloud.utils.db.Encrypt;
import org.apache.cloudstack.api.InternalIdentity;
@Entity
@Table(name = "domain_details")
public class DomainDetailVO implements InternalIdentity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(name = "domain_id")
private long domainId;
@Column(name = "name")
private String name;
@Encrypt
@Column(name = "value")
private String value;
protected DomainDetailVO() {
}
public DomainDetailVO(long domainId, String name, String value) {
this.domainId = domainId;
this.name = name;
this.value = value;
}
public long getDomainId() {
return domainId;
}
public String getName() {
return name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public long getId() {
return id;
}
}

View File

@ -0,0 +1,34 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.domain.dao;
import java.util.Map;
import com.cloud.domain.DomainDetailVO;
import com.cloud.utils.db.GenericDao;
public interface DomainDetailsDao extends GenericDao<DomainDetailVO, Long> {
Map<String, String> findDetails(long domainId);
void persist(long domainId, Map<String, String> details);
DomainDetailVO findDetail(long domainId, String name);
void deleteDetails(long domainId);
void update(long domainId, Map<String, String> details);
}

View File

@ -0,0 +1,104 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.domain.dao;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.cloud.domain.DomainDetailVO;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.db.TransactionLegacy;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.ConfigKey.Scope;
import org.apache.cloudstack.framework.config.ScopedConfigStorage;
public class DomainDetailsDaoImpl extends GenericDaoBase<DomainDetailVO, Long> implements DomainDetailsDao, ScopedConfigStorage {
protected final SearchBuilder<DomainDetailVO> domainSearch;
protected DomainDetailsDaoImpl() {
domainSearch = createSearchBuilder();
domainSearch.and("domainId", domainSearch.entity().getDomainId(), Op.EQ);
domainSearch.done();
}
@Override
public Map<String, String> findDetails(long domainId) {
QueryBuilder<DomainDetailVO> sc = QueryBuilder.create(DomainDetailVO.class);
sc.and(sc.entity().getDomainId(), Op.EQ, domainId);
List<DomainDetailVO> results = sc.list();
Map<String, String> details = new HashMap<String, String>(results.size());
for (DomainDetailVO r : results) {
details.put(r.getName(), r.getValue());
}
return details;
}
@Override
public void persist(long domainId, Map<String, String> details) {
TransactionLegacy txn = TransactionLegacy.currentTxn();
txn.start();
SearchCriteria<DomainDetailVO> sc = domainSearch.create();
sc.setParameters("domainId", domainId);
expunge(sc);
for (Map.Entry<String, String> detail : details.entrySet()) {
DomainDetailVO vo = new DomainDetailVO(domainId, detail.getKey(), detail.getValue());
persist(vo);
}
txn.commit();
}
@Override
public DomainDetailVO findDetail(long domainId, String name) {
QueryBuilder<DomainDetailVO> sc = QueryBuilder.create(DomainDetailVO.class);
sc.and(sc.entity().getDomainId(), Op.EQ, domainId);
sc.and(sc.entity().getName(), Op.EQ, name);
return sc.find();
}
@Override
public void deleteDetails(long domainId) {
SearchCriteria<DomainDetailVO> sc = domainSearch.create();
sc.setParameters("domainId", domainId);
List<DomainDetailVO> results = search(sc, null);
for (DomainDetailVO result : results) {
remove(result.getId());
}
}
@Override
public void update(long domainId, Map<String, String> details) {
Map<String, String> oldDetails = findDetails(domainId);
oldDetails.putAll(details);
persist(domainId, oldDetails);
}
@Override
public Scope getScope() {
return Scope.Domain;
}
@Override
public String getConfigValue(long id, ConfigKey<?> key) {
DomainDetailVO vo = findDetail(id, key.key());
return vo == null ? null : vo.getValue();
}
}

View File

@ -31,7 +31,7 @@ import com.cloud.utils.exception.CloudRuntimeException;
public class ConfigKey<T> {
public static enum Scope {
Global, Zone, Cluster, StoragePool, Account, ManagementServer, ImageStore
Global, Zone, Cluster, StoragePool, Account, ManagementServer, ImageStore, Domain
}
private final String _category;

View File

@ -85,6 +85,7 @@ public class ConfigDepotImpl implements ConfigDepot, ConfigDepotAdmin {
_scopeLevelConfigsMap.put(ConfigKey.Scope.StoragePool, new HashSet<ConfigKey<?>>());
_scopeLevelConfigsMap.put(ConfigKey.Scope.Account, new HashSet<ConfigKey<?>>());
_scopeLevelConfigsMap.put(ConfigKey.Scope.ImageStore, new HashSet<ConfigKey<?>>());
_scopeLevelConfigsMap.put(ConfigKey.Scope.Domain, new HashSet<ConfigKey<?>>());
}
@Override

View File

@ -140,6 +140,7 @@ import com.cloud.deploy.DeploymentPlanner;
import com.cloud.deploy.DeploymentPlanningManager;
import com.cloud.deploy.dao.PlannerHostReservationDaoImpl;
import com.cloud.domain.dao.DomainDaoImpl;
import com.cloud.domain.dao.DomainDetailsDaoImpl;
import com.cloud.event.dao.EventDaoImpl;
import com.cloud.event.dao.EventJoinDaoImpl;
import com.cloud.event.dao.UsageEventDaoImpl;
@ -148,8 +149,8 @@ import com.cloud.host.dao.HostDaoImpl;
import com.cloud.host.dao.HostDetailsDaoImpl;
import com.cloud.host.dao.HostTagsDaoImpl;
import com.cloud.hypervisor.HypervisorGuruManagerImpl;
import com.cloud.hypervisor.dao.HypervisorCapabilitiesDaoImpl;
import com.cloud.hypervisor.XenServerGuru;
import com.cloud.hypervisor.dao.HypervisorCapabilitiesDaoImpl;
import com.cloud.network.ExternalDeviceUsageManager;
import com.cloud.network.IpAddress;
import com.cloud.network.IpAddressManagerImpl;
@ -169,8 +170,8 @@ import com.cloud.network.as.dao.CounterDaoImpl;
import com.cloud.network.dao.AccountGuestVlanMapDaoImpl;
import com.cloud.network.dao.FirewallRulesCidrsDaoImpl;
import com.cloud.network.dao.FirewallRulesDaoImpl;
import com.cloud.network.dao.IPAddressDaoImpl;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.IPAddressDaoImpl;
import com.cloud.network.dao.LBHealthCheckPolicyDaoImpl;
import com.cloud.network.dao.LBStickinessPolicyDaoImpl;
import com.cloud.network.dao.LoadBalancerDaoImpl;
@ -308,7 +309,7 @@ import com.cloud.vm.snapshot.dao.VMSnapshotDaoImpl;
ConditionDaoImpl.class, ConfigurationDaoImpl.class, ConfigurationManagerImpl.class, ConfigurationServerImpl.class, ConsoleProxyDaoImpl.class,
ContrailElementImpl.class, ContrailGuru.class, ContrailManagerImpl.class, CounterDaoImpl.class, DataCenterDaoImpl.class, DataCenterDetailsDaoImpl.class, DataCenterIpAddressDaoImpl.class,
DataCenterJoinDaoImpl.class, DataCenterLinkLocalIpAddressDaoImpl.class, DataCenterVnetDaoImpl.class, DcDetailsDaoImpl.class, DedicatedResourceDaoImpl.class,
DiskOfferingDaoImpl.class, DiskOfferingJoinDaoImpl.class, DomainDaoImpl.class, DomainManagerImpl.class, DomainRouterDaoImpl.class, DomainRouterJoinDaoImpl.class,
DiskOfferingDaoImpl.class, DiskOfferingJoinDaoImpl.class, DomainDaoImpl.class, DomainDetailsDaoImpl.class, DomainManagerImpl.class, DomainRouterDaoImpl.class, DomainRouterJoinDaoImpl.class,
EventDaoImpl.class, EventJoinDaoImpl.class, EventUtils.class, ExtensionRegistry.class, FirewallManagerImpl.class, FirewallRulesCidrsDaoImpl.class,
FirewallRulesDaoImpl.class, GuestOSCategoryDaoImpl.class, GuestOSDaoImpl.class, HostDaoImpl.class, HostDetailsDaoImpl.class, HostJoinDaoImpl.class,
HostPodDaoImpl.class, HostTagsDaoImpl.class, HostTransferMapDaoImpl.class, HypervisorCapabilitiesDaoImpl.class, HypervisorGuruManagerImpl.class,

View File

@ -317,7 +317,13 @@ public class MockAccountManager extends ManagerBase implements AccountManager {
return false;
}
@Override public boolean moveUser(MoveUserCmd moveUserCmd) {
@Override
public boolean moveUser(MoveUserCmd moveUserCmd) {
return false;
}
@Override
public boolean moveUser(long id, Long domainId, long accountId) {
return false;
}

View File

@ -37,9 +37,9 @@
<configuration>
<sources>
<fileset>
<directory>test/groovy</directory>
<directory>test</directory>
<includes>
<include>**/*.groovy</include>
<include>groovy/**/*.groovy</include>
</includes>
</fileset>
</sources>
@ -70,7 +70,8 @@
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*Spec*</include>
<include>**/*Spec.groovy</include>
<include>**/*Test.java</include>
</includes>
</configuration>
</plugin>
@ -90,6 +91,7 @@
</plugin>
</plugins>
<testSourceDirectory>test</testSourceDirectory>
</build>
<dependencies>
<!-- Mandatory dependencies for using Spock -->

View File

@ -49,7 +49,7 @@ import com.cloud.utils.Pair;
* @deprecated as of 4.3 use the new api {@link LdapAddConfigurationCmd}
*/
@Deprecated
@APICommand(name = "ldapConfig", description = "Configure the LDAP context for this site.", responseObject = LDAPConfigResponse.class, since = "3.0.0",
@APICommand(name = "ldapConfig", description = "(Deprecated, use addLdapConfiguration) Configure the LDAP context for this site.", responseObject = LDAPConfigResponse.class, since = "3.0.0",
requestHasSensitiveInfo = true, responseHasSensitiveInfo = false)
public class LDAPConfigCmd extends BaseCmd {
@ -190,8 +190,8 @@ public class LDAPConfigCmd extends BaseCmd {
if (result.second() > 0) {
boolean useSSlConfig = _ldapConfiguration.getSSLStatus();
String searchBaseConfig = _ldapConfiguration.getBaseDn();
String bindDnConfig = _ldapConfiguration.getBindPrincipal();
String searchBaseConfig = _ldapConfiguration.getBaseDn(null);
String bindDnConfig = _ldapConfiguration.getBindPrincipal(null);
for (LdapConfigurationVO ldapConfigurationVO : result.first()) {
responses.add(createLDAPConfigResponse(ldapConfigurationVO.getHostname(), ldapConfigurationVO.getPort(), useSSlConfig, null, searchBaseConfig,
bindDnConfig));
@ -226,7 +226,7 @@ public class LDAPConfigCmd extends BaseCmd {
}
private boolean updateLDAP() {
_ldapManager.addConfiguration(hostname, port);
_ldapManager.addConfiguration(hostname, port, null);
/**
* There is no query filter now. It is derived from ldap.user.object and ldap.search.group.principle

View File

@ -35,7 +35,7 @@ import com.cloud.utils.Pair;
* @deprecated as of 4.3 use the new api {@link LdapDeleteConfigurationCmd}
*/
@Deprecated
@APICommand(name = "ldapRemove", description = "Remove the LDAP context for this site.", responseObject = LDAPConfigResponse.class, since = "3.0.1",
@APICommand(name = "ldapRemove", description = "(Deprecated , use deleteLdapConfiguration) Remove the LDAP context for this site.", responseObject = LDAPConfigResponse.class, since = "3.0.1",
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class LDAPRemoveCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(LDAPRemoveCmd.class.getName());
@ -60,7 +60,7 @@ public class LDAPRemoveCmd extends BaseCmd {
LdapListConfigurationCmd listConfigurationCmd = new LdapListConfigurationCmd(_ldapManager);
Pair<List<? extends LdapConfigurationVO>, Integer> result = _ldapManager.listConfigurations(listConfigurationCmd);
for (LdapConfigurationVO config : result.first()) {
_ldapManager.deleteConfiguration(config.getHostname());
_ldapManager.deleteConfiguration(config.getHostname(), 0, null);
}
return true;
}

View File

@ -18,6 +18,8 @@ package org.apache.cloudstack.api.command;
import javax.inject.Inject;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
@ -40,12 +42,15 @@ public class LdapAddConfigurationCmd extends BaseCmd {
@Inject
private LdapManager _ldapManager;
@Parameter(name = "hostname", type = CommandType.STRING, required = true, description = "Hostname")
@Parameter(name = ApiConstants.HOST_NAME, type = CommandType.STRING, required = true, description = "Hostname")
private String hostname;
@Parameter(name = "port", type = CommandType.INTEGER, required = true, description = "Port")
@Parameter(name = ApiConstants.PORT, type = CommandType.INTEGER, required = true, description = "Port")
private int port;
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = false, entityType = DomainResponse.class, description = "linked domain")
private Long domainId;
public LdapAddConfigurationCmd() {
super();
}
@ -58,7 +63,7 @@ public class LdapAddConfigurationCmd extends BaseCmd {
@Override
public void execute() throws ServerApiException {
try {
final LdapConfigurationResponse response = _ldapManager.addConfiguration(hostname, port);
final LdapConfigurationResponse response = _ldapManager.addConfiguration(hostname, port, domainId);
response.setObjectName("LdapAddConfiguration");
response.setResponseName(getCommandName());
setResponseObject(response);
@ -86,6 +91,10 @@ public class LdapAddConfigurationCmd extends BaseCmd {
return port;
}
public Long getDomainId() {
return domainId;
}
public void setHostname(final String hostname) {
this.hostname = hostname;
}

View File

@ -139,7 +139,7 @@ public class LdapCreateAccountCmd extends BaseCmd {
Long finalDomainId = getDomainId();
callContext.setEventDetails("Account Name: " + finalAccountName + ", Domain Id:" + finalDomainId);
try {
final LdapUser user = _ldapManager.getUser(username);
final LdapUser user = _ldapManager.getUser(username, domainId);
validateUser(user);
final UserAccount userAccount = createCloudstackUserAccount(user, finalAccountName, finalDomainId);
if (userAccount != null) {

View File

@ -18,6 +18,8 @@ package org.apache.cloudstack.api.command;
import javax.inject.Inject;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
@ -40,9 +42,16 @@ public class LdapDeleteConfigurationCmd extends BaseCmd {
@Inject
private LdapManager _ldapManager;
@Parameter(name = "hostname", type = CommandType.STRING, required = true, description = "Hostname")
@Parameter(name = ApiConstants.HOST_NAME, type = CommandType.STRING, required = true, description = "Hostname")
private String hostname;
@Parameter(name = ApiConstants.PORT, type = CommandType.INTEGER, required = false, description = "port")
private int port;
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = false, entityType = DomainResponse.class, description = "linked domain")
private Long domainId;
public LdapDeleteConfigurationCmd() {
super();
}
@ -52,10 +61,22 @@ public class LdapDeleteConfigurationCmd extends BaseCmd {
_ldapManager = ldapManager;
}
public String getHostname() {
return hostname;
}
public int getPort() {
return port;
}
public Long getDomainId() {
return domainId;
}
@Override
public void execute() throws ServerApiException {
try {
final LdapConfigurationResponse response = _ldapManager.deleteConfiguration(hostname);
final LdapConfigurationResponse response = _ldapManager.deleteConfiguration(this);
response.setObjectName("LdapDeleteConfiguration");
response.setResponseName(getCommandName());
setResponseObject(response);

View File

@ -142,9 +142,9 @@ public class LdapImportUsersCmd extends BaseListCmd {
try {
if (StringUtils.isNotBlank(groupName)) {
users = _ldapManager.getUsersInGroup(groupName);
users = _ldapManager.getUsersInGroup(groupName, domainId);
} else {
users = _ldapManager.getUsers();
users = _ldapManager.getUsers(domainId);
}
} catch (NoLdapUserMatchingQueryException ex) {
users = new ArrayList<LdapUser>();

View File

@ -21,6 +21,8 @@ import java.util.List;
import javax.inject.Inject;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
@ -44,12 +46,15 @@ public class LdapListConfigurationCmd extends BaseListCmd {
@Inject
private LdapManager _ldapManager;
@Parameter(name = "hostname", type = CommandType.STRING, required = false, description = "Hostname")
@Parameter(name = ApiConstants. HOST_NAME, type = CommandType.STRING, required = false, description = "Hostname")
private String hostname;
@Parameter(name = "port", type = CommandType.INTEGER, required = false, description = "Port")
@Parameter(name = ApiConstants.PORT, type = CommandType.INTEGER, required = false, description = "Port")
private int port;
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = false, entityType = DomainResponse.class, description = "linked domain")
private Long domainId;
public LdapListConfigurationCmd() {
super();
}
@ -97,6 +102,10 @@ public class LdapListConfigurationCmd extends BaseListCmd {
return port;
}
public Long getDomainId() {
return domainId;
}
public void setHostname(final String hostname) {
this.hostname = hostname;
}
@ -104,4 +113,8 @@ public class LdapListConfigurationCmd extends BaseListCmd {
public void setPort(final int port) {
this.port = port;
}
public void setDomainId(final Long domainId) {
this.domainId = domainId;
}
}

View File

@ -83,7 +83,7 @@ public class LdapListUsersCmd extends BaseListCmd {
List<LdapUserResponse> ldapResponses = null;
final ListResponse<LdapUserResponse> response = new ListResponse<LdapUserResponse>();
try {
final List<LdapUser> users = _ldapManager.getUsers();
final List<LdapUser> users = _ldapManager.getUsers(null);
ldapResponses = createLdapUserResponse(users);
} catch (final NoLdapUserMatchingQueryException ex) {
ldapResponses = new ArrayList<LdapUserResponse>();

View File

@ -0,0 +1,142 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cloudstack.api.command;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.Account;
import com.cloud.user.User;
import com.cloud.user.UserAccount;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.LinkAccountToLdapResponse;
import org.apache.cloudstack.api.response.LinkDomainToLdapResponse;
import org.apache.cloudstack.ldap.LdapManager;
import org.apache.cloudstack.ldap.LdapUser;
import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException;
import org.apache.log4j.Logger;
import javax.inject.Inject;
import java.util.UUID;
@APICommand(name = LinkAccountToLdapCmd.APINAME, description = "link a cloudstack account to a group or OU in ldap", responseObject = LinkDomainToLdapResponse.class, since = "4.11.0",
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {RoleType.Admin,RoleType.DomainAdmin})
public class LinkAccountToLdapCmd extends BaseCmd {
public static final Logger LOGGER = Logger.getLogger(LinkAccountToLdapCmd.class.getName());
public static final String APINAME = "linkAccountToLdap";
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = true, entityType = DomainResponse.class, description = "The id of the domain that is to contain the linked account.")
private Long domainId;
@Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, required = false, description = "type of the ldap name. GROUP or OU, defaults to GROUP")
private String type;
@Parameter(name = ApiConstants.LDAP_DOMAIN, type = CommandType.STRING, required = true, description = "name of the group or OU in LDAP")
private String ldapDomain;
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, required = true, description = "name of the account, it will be created if it does not exist")
private String accountName;
@Parameter(name = ApiConstants.ADMIN, type = CommandType.STRING, required = false, description = "domain admin username in LDAP ")
private String admin;
@Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, required = true, description = "Type of the account to auto import. Specify 0 for user and 2 for "
+ "domain admin")
private short accountType;
@Inject
private LdapManager _ldapManager;
@Override
public void execute() throws ServerApiException {
try {
LinkAccountToLdapResponse response = _ldapManager.linkAccountToLdap(this);
if (admin != null) {
LdapUser ldapUser = null;
try {
ldapUser = _ldapManager.getUser(admin, type, ldapDomain, domainId);
} catch (NoLdapUserMatchingQueryException e) {
LOGGER.debug("no ldap user matching username " + admin + " in the given group/ou", e);
}
if (ldapUser != null && !ldapUser.isDisabled()) {
Account account = _accountService.getActiveAccountByName(admin, domainId);
if (account == null) {
try {
UserAccount userAccount = _accountService
.createUserAccount(admin, "", ldapUser.getFirstname(), ldapUser.getLastname(), ldapUser.getEmail(), null, admin, Account.ACCOUNT_TYPE_DOMAIN_ADMIN, RoleType.DomainAdmin.getId(), domainId, null, null, UUID.randomUUID().toString(),
UUID.randomUUID().toString(), User.Source.LDAP);
response.setAdminId(String.valueOf(userAccount.getAccountId()));
LOGGER.info("created an account with name " + admin + " in the given domain " + domainId);
} catch (Exception e) {
LOGGER.info("an exception occurred while creating account with name " + admin + " in domain " + domainId, e);
}
} else {
LOGGER.debug("an account with name " + admin + " already exists in the domain " + domainId);
}
} else {
LOGGER.debug("ldap user with username " + admin + " is disabled in the given group/ou");
}
}
response.setObjectName(APINAME);
response.setResponseName(getCommandName());
setResponseObject(response);
} catch (final InvalidParameterValueException e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.toString());
}
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
public Long getDomainId() {
return domainId;
}
public String getType() {
return type;
}
public String getLdapDomain() {
return ldapDomain;
}
public String getAccountName() {
return accountName;
}
public String getAdmin() {
return admin;
}
public short getAccountType() {
return accountType;
}
}

View File

@ -54,6 +54,10 @@ public class LinkDomainToLdapCmd extends BaseCmd {
@Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, required = true, description = "type of the ldap name. GROUP or OU")
private String type;
@Parameter(name = ApiConstants.LDAP_DOMAIN, type = CommandType.STRING, required = true, description = "name of the group or OU in LDAP")
private String ldapDomain;
@Deprecated
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "name of the group or OU in LDAP")
private String name;
@ -67,14 +71,35 @@ public class LinkDomainToLdapCmd extends BaseCmd {
@Inject
private LdapManager _ldapManager;
public Long getDomainId() {
return domainId;
}
public String getType() {
return type;
}
public String getLdapDomain() {
return ldapDomain == null ? name : ldapDomain;
}
public String getAdmin() {
return admin;
}
public short getAccountType() {
return accountType;
}
@Override
public void execute() throws ServerApiException {
try {
LinkDomainToLdapResponse response = _ldapManager.linkDomainToLdap(domainId, type, name, accountType);
LinkDomainToLdapResponse response = _ldapManager.linkDomainToLdap(this);
if(admin!=null) {
LdapUser ldapUser = null;
try {
ldapUser = _ldapManager.getUser(admin, type, name);
ldapUser = _ldapManager.getUser(admin, type, getLdapDomain(), domainId);
} catch (NoLdapUserMatchingQueryException e) {
s_logger.debug("no ldap user matching username " + admin + " in the given group/ou", e);
}

View File

@ -18,31 +18,44 @@ package org.apache.cloudstack.api.response;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import com.cloud.serializer.Param;
import org.apache.cloudstack.api.EntityReference;
import org.apache.cloudstack.ldap.LdapConfiguration;
@EntityReference(value = LdapConfiguration.class)
public class LdapConfigurationResponse extends BaseResponse {
@SerializedName("hostname")
@Param(description = "hostname")
@SerializedName(ApiConstants.HOST_NAME)
@Param(description = "name of the host running the ldap server")
private String hostname;
@SerializedName("port")
@Param(description = "port")
@SerializedName(ApiConstants.PORT)
@Param(description = "port teh ldap server is running on")
private int port;
@SerializedName(ApiConstants.DOMAIN_ID)
@Param(description = "linked domain")
private String domainId;
public LdapConfigurationResponse() {
super();
}
public LdapConfigurationResponse(final String hostname) {
super();
this.hostname = hostname;
setHostname(hostname);
}
public LdapConfigurationResponse(final String hostname, final int port) {
this.hostname = hostname;
this.port = port;
this(hostname);
setPort(port);
}
public LdapConfigurationResponse(final String hostname, final int port, final String domainId) {
this(hostname, port);
setDomainId(domainId);
}
public String getHostname() {
@ -60,4 +73,12 @@ public class LdapConfigurationResponse extends BaseResponse {
public void setPort(final int port) {
this.port = port;
}
public String getDomainId() {
return domainId;
}
public void setDomainId(String domainId) {
this.domainId = domainId;
}
}

View File

@ -0,0 +1,85 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cloudstack.api.response;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
public class LinkAccountToLdapResponse extends BaseResponse {
@SerializedName(ApiConstants.DOMAIN_ID)
@Param(description = "id of the Domain which is linked to LDAP")
private String domainId;
@SerializedName(ApiConstants.LDAP_DOMAIN)
@Param(description = "name of the group or OU in LDAP which is linked to the domain")
private String ldapDomain;
@SerializedName(ApiConstants.TYPE)
@Param(description = "type of the name in LDAP which is linke to the domain")
private String type;
@SerializedName(ApiConstants.ACCOUNT_TYPE)
@Param(description = "Type of the account to auto import")
private short accountType;
@SerializedName(ApiConstants.ACCOUNT_ID)
@Param(description = "Domain Admin accountId that is created")
private String adminId;
@SerializedName(ApiConstants.ACCOUNT)
@Param(description = "name of the account")
private String accountName;
public LinkAccountToLdapResponse(String domainId, String type, String ldapDomain, short accountType, String adminId, String accountName) {
this.domainId = domainId;
this.type = type;
this.ldapDomain = ldapDomain;
this.accountType = accountType;
this.adminId = adminId;
this.accountName = accountName;
}
public String getDomainId() {
return domainId;
}
public String getLdapDomain() {
return ldapDomain;
}
public String getType() {
return type;
}
public short getAccountType() {
return accountType;
}
public String getAdminId() {
return adminId;
}
public void setAdminId(String adminId) {
this.adminId = adminId;
}
}

View File

@ -66,11 +66,6 @@ public class LinkDomainToLdapResponse extends BaseResponse {
return ldapDomain == null ? name : ldapDomain;
}
@Deprecated
public String getName() {
return ldapDomain == null ? name : ldapDomain;
}
public String getType() {
return type;
}

View File

@ -36,38 +36,38 @@ public class ADLdapUserManagerImpl extends OpenLdapUserManagerImpl implements Ld
private static final String MICROSOFT_AD_MEMBERS_FILTER = "memberOf";
@Override
public List<LdapUser> getUsersInGroup(String groupName, LdapContext context) throws NamingException {
public List<LdapUser> getUsersInGroup(String groupName, LdapContext context, Long domainId) throws NamingException {
if (StringUtils.isBlank(groupName)) {
throw new IllegalArgumentException("ldap group name cannot be blank");
}
String basedn = _ldapConfiguration.getBaseDn();
String basedn = _ldapConfiguration.getBaseDn(domainId);
if (StringUtils.isBlank(basedn)) {
throw new IllegalArgumentException("ldap basedn is not configured");
}
final SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(_ldapConfiguration.getScope());
searchControls.setReturningAttributes(_ldapConfiguration.getReturnAttributes());
searchControls.setReturningAttributes(_ldapConfiguration.getReturnAttributes(domainId));
NamingEnumeration<SearchResult> results = context.search(basedn, generateADGroupSearchFilter(groupName), searchControls);
NamingEnumeration<SearchResult> results = context.search(basedn, generateADGroupSearchFilter(groupName, domainId), searchControls);
final List<LdapUser> users = new ArrayList<LdapUser>();
while (results.hasMoreElements()) {
final SearchResult result = results.nextElement();
users.add(createUser(result));
users.add(createUser(result, domainId));
}
return users;
}
private String generateADGroupSearchFilter(String groupName) {
private String generateADGroupSearchFilter(String groupName, Long domainId) {
final StringBuilder userObjectFilter = new StringBuilder();
userObjectFilter.append("(objectClass=");
userObjectFilter.append(_ldapConfiguration.getUserObject());
userObjectFilter.append(_ldapConfiguration.getUserObject(domainId));
userObjectFilter.append(")");
final StringBuilder memberOfFilter = new StringBuilder();
String groupCnName = _ldapConfiguration.getCommonNameAttribute() + "=" +groupName + "," + _ldapConfiguration.getBaseDn();
memberOfFilter.append("(").append(getMemberOfAttribute()).append("=");
String groupCnName = _ldapConfiguration.getCommonNameAttribute() + "=" +groupName + "," + _ldapConfiguration.getBaseDn(domainId);
memberOfFilter.append("(").append(getMemberOfAttribute(domainId)).append("=");
memberOfFilter.append(groupCnName);
memberOfFilter.append(")");
@ -94,8 +94,8 @@ public class ADLdapUserManagerImpl extends OpenLdapUserManagerImpl implements Ld
return isDisabledUser;
}
protected String getMemberOfAttribute() {
if(_ldapConfiguration.isNestedGroupsEnabled()) {
protected String getMemberOfAttribute(final Long domainId) {
if(_ldapConfiguration.isNestedGroupsEnabled(domainId)) {
return MICROSOFT_AD_NESTED_MEMBERS_FILTER;
} else {
return MICROSOFT_AD_MEMBERS_FILTER;

View File

@ -16,6 +16,8 @@
// under the License.
package org.apache.cloudstack.ldap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@ -56,60 +58,181 @@ public class LdapAuthenticator extends AdapterBase implements UserAuthenticator
@Override
public Pair<Boolean, ActionOnFailedAuthentication> authenticate(final String username, final String password, final Long domainId, final Map<String, Object[]> requestParameters) {
Pair<Boolean, ActionOnFailedAuthentication> rc = new Pair<Boolean, ActionOnFailedAuthentication>(false, null);
// TODO not allowing an empty password is a policy we shouldn't decide on. A private cloud may well want to allow this.
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
s_logger.debug("Username or Password cannot be empty");
return new Pair<Boolean, ActionOnFailedAuthentication>(false, null);
return rc;
}
boolean result = false;
ActionOnFailedAuthentication action = null;
if (_ldapManager.isLdapEnabled()) {
final UserAccount user = _userAccountDao.getUserAccount(username, domainId);
LdapTrustMapVO ldapTrustMapVO = _ldapManager.getDomainLinkedToLdap(domainId);
if(ldapTrustMapVO != null) {
try {
LdapUser ldapUser = _ldapManager.getUser(username, ldapTrustMapVO.getType().toString(), ldapTrustMapVO.getName());
if(!ldapUser.isDisabled()) {
result = _ldapManager.canAuthenticate(ldapUser.getPrincipal(), password);
if(result) {
if(user == null) {
// import user to cloudstack
createCloudStackUserAccount(ldapUser, domainId, ldapTrustMapVO.getAccountType());
} else {
enableUserInCloudStack(user);
}
}
} else {
//disable user in cloudstack
disableUserInCloudStack(user);
}
} catch (NoLdapUserMatchingQueryException e) {
s_logger.debug(e.getMessage());
List<LdapTrustMapVO> ldapTrustMapVOs = _ldapManager.getDomainLinkage(domainId);
if(ldapTrustMapVOs != null && ldapTrustMapVOs.size() > 0) {
if(ldapTrustMapVOs.size() == 1 && ldapTrustMapVOs.get(0).getAccountId() == 0) {
// We have a single mapping of a domain to an ldap group or ou
return authenticate(username, password, domainId, user, ldapTrustMapVOs.get(0));
} else {
// we are dealing with mapping of accounts in a domain to ldap groups
return authenticate(username, password, domainId, user, ldapTrustMapVOs);
}
} else {
//domain is not linked to ldap follow normal authentication
if(user != null ) {
try {
LdapUser ldapUser = _ldapManager.getUser(username);
if(!ldapUser.isDisabled()) {
result = _ldapManager.canAuthenticate(ldapUser.getPrincipal(), password);
} else {
s_logger.debug("user with principal "+ ldapUser.getPrincipal() + " is disabled in ldap");
}
} catch (NoLdapUserMatchingQueryException e) {
s_logger.debug(e.getMessage());
}
}
}
if (!result && user != null) {
action = ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT;
return authenticate(username, password, domainId, user);
}
}
return new Pair<Boolean, ActionOnFailedAuthentication>(result, action);
return rc;
}
/**
* checks if the user exists in ldap and create in cloudstack if needed.
*
* @param username login id
* @param password pass phrase
* @param domainId domain the user is trying to log on to
* @param userAccount cloudstack user object
* @param ldapTrustMapVOs the trust mappings of accounts in the domain to ldap groups
* @return false if the ldap user object does not exist, is not mapped to an account, is mapped to multiple accounts or if authenitication fails
*/
private Pair<Boolean, ActionOnFailedAuthentication> authenticate(String username, String password, Long domainId, UserAccount userAccount, List<LdapTrustMapVO> ldapTrustMapVOs) {
Pair<Boolean, ActionOnFailedAuthentication> rc = new Pair<Boolean, ActionOnFailedAuthentication>(false, null);
try {
LdapUser ldapUser = _ldapManager.getUser(username, domainId);
List<String> memberships = ldapUser.getMemberships();
List<String> mappedGroups = getMappedGroups(ldapTrustMapVOs);
mappedGroups.retainAll(memberships);
// check membership, there must be only one match in this domain
if(ldapUser.isDisabled()) {
logAndDisable(userAccount, "attempt to log on using disabled ldap user " + userAccount.getUsername(), false);
} else if(mappedGroups.size() > 1) {
logAndDisable(userAccount, "user '" + username + "' is mapped to more then one account in domain and will be disabled.", false);
} else if(mappedGroups.size() < 1) {
logAndDisable(userAccount, "user '" + username + "' is not mapped to an account in domain and will be removed.", true);
} else {
// a valid ldap configured user exists
LdapTrustMapVO mapping = _ldapManager.getLinkedLdapGroup(domainId,mappedGroups.get(0));
// we could now assert that ldapTrustMapVOs.contains(mapping);
// createUser in Account can only be done by account name not by account id
String accountName = _accountManager.getAccount(mapping.getAccountId()).getAccountName();
rc.first(_ldapManager.canAuthenticate(ldapUser.getPrincipal(), password, domainId));
// for security reasons we keep processing on faulty login attempt to not give a way information on userid existence
if (userAccount == null) {
// new user that is in ldap; authenticate and create
User user = _accountManager.createUser(username, "", ldapUser.getFirstname(), ldapUser.getLastname(), ldapUser.getEmail(), null, accountName,
domainId, UUID.randomUUID().toString(), User.Source.LDAP);
/* expected error conditions:
*
* caught in APIServlet: CloudRuntimeException("The domain " + domainId + " does not exist; unable to create user");
* caught in APIServlet: CloudRuntimeException("The user cannot be created as domain " + domain.getName() + " is being deleted");
* would have been thrown above: InvalidParameterValueException("Unable to find account " + accountName + " in domain id=" + domainId + " to create user");
* we are system user: PermissionDeniedException("Account id : " + account.getId() + " is a system account, can't add a user to it");
* serious and must be thrown: CloudRuntimeException("The user " + userName + " already exists in domain " + domainId);
* fatal system error and must be thrown: CloudRuntimeException("Failed to encode password");
*/
userAccount = _accountManager.getUserAccountById(user.getId());
} else {
// not a new user, check if mapped group has changed
if(userAccount.getAccountId() != mapping.getAccountId()) {
_accountManager.moveUser(userAccount.getId(),userAccount.getDomainId(),mapping.getAccountId());
}
// else { the user hasn't changed in ldap, the ldap group stayed the same, hurray, pass, fun thou self a lot of fun }
}
}
} catch (NoLdapUserMatchingQueryException e) {
s_logger.debug(e.getMessage());
disableUserInCloudStack(userAccount);
}
return rc;
}
private void logAndDisable(UserAccount userAccount, String msg, boolean remove) {
if (s_logger.isInfoEnabled()) {
s_logger.info(msg);
}
if(remove) {
removeUserInCloudStack(userAccount);
} else {
disableUserInCloudStack(userAccount);
}
}
private List<String> getMappedGroups(List<LdapTrustMapVO> ldapTrustMapVOs) {
List<String> groups = new ArrayList<>();
for (LdapTrustMapVO vo : ldapTrustMapVOs) {
groups.add(vo.getName());
}
return groups;
}
/**
* checks if the user exists in ldap and create in cloudstack if needed
* @param username login id
* @param password pass phrase
* @param domainId domain the user is trying to log on to
* @param user cloudstack user object
* @param ldapTrustMapVO the trust mapping for the domain to the ldap group
* @return false if the ldap user object does not exist or authenitication fails
*/
private Pair<Boolean, ActionOnFailedAuthentication> authenticate(String username, String password, Long domainId, UserAccount user, LdapTrustMapVO ldapTrustMapVO) {
Pair<Boolean, ActionOnFailedAuthentication> rc = new Pair<Boolean, ActionOnFailedAuthentication>(false, null);
try {
LdapUser ldapUser = _ldapManager.getUser(username, ldapTrustMapVO.getType().toString(), ldapTrustMapVO.getName(), domainId);
final short accountType = ldapTrustMapVO.getAccountType();
processLdapUser(password, domainId, user, rc, ldapUser, accountType);
} catch (NoLdapUserMatchingQueryException e) {
s_logger.debug(e.getMessage());
}
return rc;
}
private void processLdapUser(String password, Long domainId, UserAccount user, Pair<Boolean, ActionOnFailedAuthentication> rc, LdapUser ldapUser, short accountType) {
if(!ldapUser.isDisabled()) {
rc.first(_ldapManager.canAuthenticate(ldapUser.getPrincipal(), password, domainId));
if(rc.first()) {
if(user == null) {
// import user to cloudstack
createCloudStackUserAccount(ldapUser, domainId, accountType);
} else {
enableUserInCloudStack(user);
}
} else if(user != null) {
rc.second(ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT);
}
} else {
//disable user in cloudstack
disableUserInCloudStack(user);
}
}
/**
* checks if the user is configured both in ldap and in cloudstack.
* @param username login id
* @param password pass phrase
* @param domainId domain the user is trying to log on to
* @param user cloudstack user object
* @return false if either user object does not exist or authenitication fails
*/
private Pair<Boolean, ActionOnFailedAuthentication> authenticate(String username, String password, Long domainId, UserAccount user) {
boolean result = false;
if(user != null ) {
try {
LdapUser ldapUser = _ldapManager.getUser(username, domainId);
if(!ldapUser.isDisabled()) {
result = _ldapManager.canAuthenticate(ldapUser.getPrincipal(), password, domainId);
} else {
s_logger.debug("user with principal "+ ldapUser.getPrincipal() + " is disabled in ldap");
}
} catch (NoLdapUserMatchingQueryException e) {
s_logger.debug(e.getMessage());
}
}
return (!result && user != null) ?
new Pair<Boolean, ActionOnFailedAuthentication>(false, ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT):
new Pair<Boolean, ActionOnFailedAuthentication>(false, null);
}
private void enableUserInCloudStack(UserAccount user) {
@ -131,6 +254,12 @@ public class LdapAuthenticator extends AdapterBase implements UserAuthenticator
}
}
private void removeUserInCloudStack(UserAccount user) {
if (user != null) {
_accountManager.disableUser(user.getId());
}
}
@Override
public String encode(final String password) {
return password;

View File

@ -31,75 +31,215 @@ import org.apache.cloudstack.ldap.dao.LdapConfigurationDao;
public class LdapConfiguration implements Configurable{
private final static String factory = "com.sun.jndi.ldap.LdapCtxFactory";
private static final ConfigKey<Long> ldapReadTimeout = new ConfigKey<Long>(Long.class, "ldap.read.timeout", "Advanced", "1000",
"LDAP connection Timeout in milli sec", true, ConfigKey.Scope.Global, 1l);
private static final ConfigKey<Long> ldapReadTimeout = new ConfigKey<Long>(
Long.class,
"ldap.read.timeout",
"Advanced",
"1000",
"LDAP connection Timeout in milli sec",
true,
ConfigKey.Scope.Domain,
1l);
private static final ConfigKey<Integer> ldapPageSize = new ConfigKey<Integer>(Integer.class, "ldap.request.page.size", "Advanced", "1000",
"page size sent to ldap server on each request to get user", true, ConfigKey.Scope.Global, 1);
private static final ConfigKey<String> ldapProvider = new ConfigKey<String>(String.class, "ldap.provider", "Advanced", "openldap", "ldap provider ex:openldap, microsoftad",
true, ConfigKey.Scope.Global, null);
private static final ConfigKey<Integer> ldapPageSize = new ConfigKey<Integer>(
Integer.class,
"ldap.request.page.size",
"Advanced",
"1000",
"page size sent to ldap server on each request to get user",
true,
ConfigKey.Scope.Domain,
1);
private static final ConfigKey<Boolean> ldapEnableNestedGroups = new ConfigKey<Boolean>(Boolean.class, "ldap.nested.groups.enable", "Advanced", "true",
"if true, nested groups will also be queried", true, ConfigKey.Scope.Global, null);
private static final ConfigKey<Boolean> ldapEnableNestedGroups = new ConfigKey<Boolean>(
"Advanced",
Boolean.class,
"ldap.nested.groups.enable",
"true",
"if true, nested groups will also be queried",
true,
ConfigKey.Scope.Domain);
private static final ConfigKey<String> ldapMemberOfAttribute = new ConfigKey<String>(
"Advanced",
String.class,
"ldap.user.memberof.attribute",
"memberof",
"the reverse membership attibute for group members",
true,
ConfigKey.Scope.Domain);
private static final ConfigKey<String> ldapProvider = new ConfigKey<String>(
"Advanced",
String.class,
"ldap.provider",
"openldap",
"ldap provider ex:openldap, microsoftad",
true,
ConfigKey.Scope.Domain);
private static final ConfigKey<String> ldapBaseDn = new ConfigKey<String>(
"Advanced",
String.class,
"ldap.basedn",
null,
"Sets the basedn for LDAP",
true,
ConfigKey.Scope.Domain);
private static final ConfigKey<String> ldapBindPassword = new ConfigKey<String>(
"Advanced",
String.class,
"ldap.bind.password",
null,
"Sets the bind password for LDAP",
true,
ConfigKey.Scope.Domain);
private static final ConfigKey<String> ldapBindPrincipal = new ConfigKey<String>(
"Advanced",
String.class,
"ldap.bind.principal",
null,
"Sets the bind principal for LDAP",
true,
ConfigKey.Scope.Domain);
private static final ConfigKey<String> ldapEmailAttribute = new ConfigKey<String>(
"Advanced",
String.class,
"ldap.email.attribute",
"mail",
"Sets the email attribute used within LDAP",
true,
ConfigKey.Scope.Domain);
private static final ConfigKey<String> ldapFirstnameAttribute = new ConfigKey<String>(
"Advanced",
String.class,
"ldap.firstname.attribute",
"givenname",
"Sets the firstname attribute used within LDAP",
true,
ConfigKey.Scope.Domain);
private static final ConfigKey<String> ldapLastnameAttribute = new ConfigKey<String>(
"Advanced",
String.class, "ldap.lastname.attribute",
"sn",
"Sets the lastname attribute used within LDAP",
true,
ConfigKey.Scope.Domain);
private static final ConfigKey<String> ldapUsernameAttribute = new ConfigKey<String>(
"Advanced",
String.class,
"ldap.username.attribute",
"uid",
"Sets the username attribute used within LDAP",
true,
ConfigKey.Scope.Domain);
private static final ConfigKey<String> ldapUserObject = new ConfigKey<String>(
"Advanced",
String.class,
"ldap.user.object",
"inetOrgPerson",
"Sets the object type of users within LDAP",
true,
ConfigKey.Scope.Domain);
private static final ConfigKey<String> ldapSearchGroupPrinciple = new ConfigKey<String>(
"Advanced",
String.class,
"ldap.search.group.principle",
null,
"Sets the principle of the group that users must be a member of",
true,
ConfigKey.Scope.Domain);
private static final ConfigKey<String> ldapGroupObject = new ConfigKey<String>(
"Advanced",
String.class,
"ldap.group.object",
"groupOfUniqueNames",
"Sets the object type of groups within LDAP",
true,
ConfigKey.Scope.Domain);
private static final ConfigKey<String> ldapGroupUniqueMemberAttribute = new ConfigKey<String>(
"Advanced",
String.class,
"ldap.group.user.uniquemember",
"uniquemember",
"Sets the attribute for uniquemembers within a group",
true,
ConfigKey.Scope.Domain);
private static final ConfigKey<String> ldapTrustStore = new ConfigKey<String>(
"Advanced",
String.class,
"ldap.truststore",
null,
"Sets the path to the truststore to use for SSL",
true,
ConfigKey.Scope.Domain);
private static final ConfigKey<String> ldapTrustStorePassword = new ConfigKey<String>(
"Advanced",
String.class,
"ldap.truststore.password",
null,
"Sets the password for the truststore",
true,
ConfigKey.Scope.Domain);
private final static int scope = SearchControls.SUBTREE_SCOPE;
@Inject
private ConfigurationDao _configDao;
@Inject
private LdapConfigurationDao _ldapConfigurationDao;
public LdapConfiguration() {
}
public LdapConfiguration(final ConfigurationDao configDao, final LdapConfigurationDao ldapConfigurationDao) {
_configDao = configDao;
public LdapConfiguration(final LdapConfigurationDao ldapConfigurationDao) {
_ldapConfigurationDao = ldapConfigurationDao;
}
public String getAuthentication() {
if ((getBindPrincipal() == null) && (getBindPassword() == null)) {
@Deprecated
public LdapConfiguration(final ConfigurationDao configDao, final LdapConfigurationDao ldapConfigurationDao) {
_ldapConfigurationDao = ldapConfigurationDao;
}
public String getAuthentication(final Long domainId) {
if ((getBindPrincipal(domainId) == null) && (getBindPassword(domainId) == null)) {
return "none";
} else {
return "simple";
}
}
public String getBaseDn() {
return _configDao.getValue("ldap.basedn");
public String getBaseDn(final Long domainId) {
return ldapBaseDn.valueIn(domainId);
}
public String getBindPassword() {
return _configDao.getValue("ldap.bind.password");
public String getBindPassword(final Long domainId) {
return ldapBindPassword.valueIn(domainId);
}
public String getBindPrincipal() {
return _configDao.getValue("ldap.bind.principal");
public String getBindPrincipal(final Long domainId) {
return ldapBindPrincipal.valueIn(domainId);
}
public String getEmailAttribute() {
final String emailAttribute = _configDao.getValue("ldap.email.attribute");
return emailAttribute == null ? "mail" : emailAttribute;
public String getEmailAttribute(final Long domainId) {
return ldapEmailAttribute.valueIn(domainId);
}
public String getFactory() {
return factory;
}
public String getFirstnameAttribute() {
final String firstnameAttribute = _configDao.getValue("ldap.firstname.attribute");
return firstnameAttribute == null ? "givenname" : firstnameAttribute;
public String getFirstnameAttribute(final Long domainId) {
return ldapFirstnameAttribute.valueIn(domainId);
}
public String getLastnameAttribute() {
final String lastnameAttribute = _configDao.getValue("ldap.lastname.attribute");
return lastnameAttribute == null ? "sn" : lastnameAttribute;
public String getLastnameAttribute(final Long domainId) {
return ldapLastnameAttribute.valueIn(domainId);
}
public String getProviderUrl() {
public String getProviderUrl(final Long domainId) {
final String protocol = getSSLStatus() == true ? "ldaps://" : "ldap://";
final Pair<List<LdapConfigurationVO>, Integer> result = _ldapConfigurationDao.searchConfigurations(null, 0);
final Pair<List<LdapConfigurationVO>, Integer> result = _ldapConfigurationDao.searchConfigurations(null, 0, domainId);
final StringBuilder providerUrls = new StringBuilder();
String delim = "";
for (final LdapConfigurationVO resource : result.first()) {
@ -110,17 +250,24 @@ public class LdapConfiguration implements Configurable{
return providerUrls.toString();
}
public String[] getReturnAttributes() {
return new String[] {getUsernameAttribute(), getEmailAttribute(), getFirstnameAttribute(), getLastnameAttribute(), getCommonNameAttribute(),
getUserAccountControlAttribute()};
public String[] getReturnAttributes(final Long domainId) {
return new String[] {
getUsernameAttribute(domainId),
getEmailAttribute(domainId),
getFirstnameAttribute(domainId),
getLastnameAttribute(domainId),
getCommonNameAttribute(),
getUserAccountControlAttribute(),
getUserMemberOfAttribute(domainId)
};
}
public int getScope() {
return scope;
}
public String getSearchGroupPrinciple() {
return _configDao.getValue("ldap.search.group.principle");
public String getSearchGroupPrinciple(final Long domainId) {
return ldapSearchGroupPrinciple.valueIn(domainId);
}
public boolean getSSLStatus() {
@ -132,53 +279,51 @@ public class LdapConfiguration implements Configurable{
}
public String getTrustStore() {
return _configDao.getValue("ldap.truststore");
return ldapTrustStore.value();
}
public String getTrustStorePassword() {
return _configDao.getValue("ldap.truststore.password");
return ldapTrustStorePassword.value();
}
public String getUsernameAttribute() {
final String usernameAttribute = _configDao.getValue("ldap.username.attribute");
return usernameAttribute == null ? "uid" : usernameAttribute;
public String getUsernameAttribute(final Long domainId) {
return ldapUsernameAttribute.valueIn(domainId);
}
public String getUserObject() {
final String userObject = _configDao.getValue("ldap.user.object");
return userObject == null ? "inetOrgPerson" : userObject;
public String getUserObject(final Long domainId) {
return ldapUserObject.valueIn(domainId);
}
public String getGroupObject() {
final String groupObject = _configDao.getValue("ldap.group.object");
return groupObject == null ? "groupOfUniqueNames" : groupObject;
public String getGroupObject(final Long domainId) {
return ldapGroupObject.valueIn(domainId);
}
public String getGroupUniqueMemeberAttribute() {
final String uniqueMemberAttribute = _configDao.getValue("ldap.group.user.uniquemember");
return uniqueMemberAttribute == null ? "uniquemember" : uniqueMemberAttribute;
public String getGroupUniqueMemberAttribute(final Long domainId) {
return ldapGroupUniqueMemberAttribute.valueIn(domainId);
}
// TODO remove hard-coding
public String getCommonNameAttribute() {
return "cn";
}
// TODO remove hard-coding
public String getUserAccountControlAttribute() {
return "userAccountControl";
}
public Long getReadTimeout() {
return ldapReadTimeout.value();
public Long getReadTimeout(final Long domainId) {
return ldapReadTimeout.valueIn(domainId);
}
public Integer getLdapPageSize() {
return ldapPageSize.value();
public Integer getLdapPageSize(final Long domainId) {
return ldapPageSize.valueIn(domainId);
}
public LdapUserManager.Provider getLdapProvider() {
public LdapUserManager.Provider getLdapProvider(final Long domainId) {
LdapUserManager.Provider provider;
try {
provider = LdapUserManager.Provider.valueOf(ldapProvider.value().toUpperCase());
provider = LdapUserManager.Provider.valueOf(ldapProvider.valueIn(domainId).toUpperCase());
} catch (IllegalArgumentException ex) {
//openldap is the default
provider = LdapUserManager.Provider.OPENLDAP;
@ -186,8 +331,12 @@ public class LdapConfiguration implements Configurable{
return provider;
}
public boolean isNestedGroupsEnabled() {
return ldapEnableNestedGroups.value();
public boolean isNestedGroupsEnabled(final Long domainId) {
return ldapEnableNestedGroups.valueIn(domainId);
}
public static String getUserMemberOfAttribute(final Long domainId) {
return ldapMemberOfAttribute.valueIn(domainId);
}
@Override
@ -197,6 +346,25 @@ public class LdapConfiguration implements Configurable{
@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {ldapReadTimeout, ldapPageSize, ldapProvider, ldapEnableNestedGroups};
return new ConfigKey<?>[]{
ldapReadTimeout,
ldapPageSize,
ldapProvider,
ldapEnableNestedGroups,
ldapBaseDn,
ldapBindPassword,
ldapBindPrincipal,
ldapEmailAttribute,
ldapFirstnameAttribute,
ldapLastnameAttribute,
ldapUsernameAttribute,
ldapUserObject,
ldapSearchGroupPrinciple,
ldapGroupObject,
ldapGroupUniqueMemberAttribute,
ldapTrustStore,
ldapTrustStorePassword,
ldapMemberOfAttribute
};
}
}
}

View File

@ -39,12 +39,16 @@ public class LdapConfigurationVO implements InternalIdentity {
@Column(name = "port")
private int port;
@Column(name = "domain_id")
private Long domainId;
public LdapConfigurationVO() {
}
public LdapConfigurationVO(final String hostname, final int port) {
public LdapConfigurationVO(final String hostname, final int port, final Long domainId) {
this.hostname = hostname;
this.port = port;
this.domainId = domainId;
}
public String getHostname() {
@ -60,6 +64,10 @@ public class LdapConfigurationVO implements InternalIdentity {
return port;
}
public Long getDomainId() {
return domainId;
}
public void setId(final long id) {
this.id = id;
}

View File

@ -40,29 +40,31 @@ public class LdapContextFactory {
_ldapConfiguration = ldapConfiguration;
}
public LdapContext createBindContext() throws NamingException, IOException {
return createBindContext(null);
// TODO add optional domain (optional only for backwards compatibility)
public LdapContext createBindContext(Long domainId) throws NamingException, IOException {
return createBindContext(null, domainId);
}
public LdapContext createBindContext(final String providerUrl) throws NamingException, IOException {
final String bindPrincipal = _ldapConfiguration.getBindPrincipal();
final String bindPassword = _ldapConfiguration.getBindPassword();
return createInitialDirContext(bindPrincipal, bindPassword, providerUrl, true);
// TODO add optional domain (optional only for backwards compatibility)
public LdapContext createBindContext(final String providerUrl, Long domainId) throws NamingException, IOException {
final String bindPrincipal = _ldapConfiguration.getBindPrincipal(domainId);
final String bindPassword = _ldapConfiguration.getBindPassword(domainId);
return createInitialDirContext(bindPrincipal, bindPassword, providerUrl, true, domainId);
}
private LdapContext createInitialDirContext(final String principal, final String password, final boolean isSystemContext) throws NamingException, IOException {
return createInitialDirContext(principal, password, null, isSystemContext);
private LdapContext createInitialDirContext(final String principal, final String password, final boolean isSystemContext, Long domainId) throws NamingException, IOException {
return createInitialDirContext(principal, password, null, isSystemContext, domainId);
}
private LdapContext createInitialDirContext(final String principal, final String password, final String providerUrl, final boolean isSystemContext)
private LdapContext createInitialDirContext(final String principal, final String password, final String providerUrl, final boolean isSystemContext, Long domainId)
throws NamingException, IOException {
Hashtable<String, String> environment = getEnvironment(principal, password, providerUrl, isSystemContext);
Hashtable<String, String> environment = getEnvironment(principal, password, providerUrl, isSystemContext, domainId);
s_logger.debug("initializing ldap with provider url: " + environment.get(Context.PROVIDER_URL));
return new InitialLdapContext(environment, null);
}
public LdapContext createUserContext(final String principal, final String password) throws NamingException, IOException {
return createInitialDirContext(principal, password, false);
public LdapContext createUserContext(final String principal, final String password, Long domainId) throws NamingException, IOException {
return createInitialDirContext(principal, password, false, domainId);
}
private void enableSSL(final Hashtable<String, String> environment) {
@ -76,19 +78,19 @@ public class LdapContextFactory {
}
}
private Hashtable<String, String> getEnvironment(final String principal, final String password, final String providerUrl, final boolean isSystemContext) {
private Hashtable<String, String> getEnvironment(final String principal, final String password, final String providerUrl, final boolean isSystemContext, Long domainId) {
final String factory = _ldapConfiguration.getFactory();
final String url = providerUrl == null ? _ldapConfiguration.getProviderUrl() : providerUrl;
final String url = providerUrl == null ? _ldapConfiguration.getProviderUrl(domainId) : providerUrl;
final Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, factory);
environment.put(Context.PROVIDER_URL, url);
environment.put("com.sun.jndi.ldap.read.timeout", _ldapConfiguration.getReadTimeout().toString());
environment.put("com.sun.jndi.ldap.read.timeout", _ldapConfiguration.getReadTimeout(domainId).toString());
environment.put("com.sun.jndi.ldap.connect.pool", "true");
enableSSL(environment);
setAuthentication(environment, isSystemContext);
setAuthentication(environment, isSystemContext, domainId);
if (principal != null) {
environment.put(Context.SECURITY_PRINCIPAL, principal);
@ -101,8 +103,8 @@ public class LdapContextFactory {
return environment;
}
private void setAuthentication(final Hashtable<String, String> environment, final boolean isSystemContext) {
final String authentication = _ldapConfiguration.getAuthentication();
private void setAuthentication(final Hashtable<String, String> environment, final boolean isSystemContext, final Long domainId) {
final String authentication = _ldapConfiguration.getAuthentication(domainId);
if ("none".equals(authentication) && !isSystemContext) {
environment.put(Context.SECURITY_AUTHENTICATION, "simple");

View File

@ -18,36 +18,48 @@ package org.apache.cloudstack.ldap;
import java.util.List;
import org.apache.cloudstack.api.command.LdapAddConfigurationCmd;
import org.apache.cloudstack.api.command.LdapDeleteConfigurationCmd;
import org.apache.cloudstack.api.command.LdapListConfigurationCmd;
import org.apache.cloudstack.api.command.LinkAccountToLdapCmd;
import org.apache.cloudstack.api.command.LinkDomainToLdapCmd;
import org.apache.cloudstack.api.response.LdapConfigurationResponse;
import org.apache.cloudstack.api.response.LdapUserResponse;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.utils.Pair;
import com.cloud.utils.component.PluggableService;
import org.apache.cloudstack.api.response.LinkAccountToLdapResponse;
import org.apache.cloudstack.api.response.LinkDomainToLdapResponse;
public interface LdapManager extends PluggableService {
enum LinkType { GROUP, OU;}
LdapConfigurationResponse addConfiguration(String hostname, int port) throws InvalidParameterValueException;
LdapConfigurationResponse addConfiguration(final LdapAddConfigurationCmd cmd) throws InvalidParameterValueException;
boolean canAuthenticate(String principal, String password);
@Deprecated
LdapConfigurationResponse addConfiguration(String hostname, int port, Long domainId) throws InvalidParameterValueException;
boolean canAuthenticate(String principal, String password, final Long domainId);
LdapConfigurationResponse createLdapConfigurationResponse(LdapConfigurationVO configuration);
LdapUserResponse createLdapUserResponse(LdapUser user);
LdapConfigurationResponse deleteConfiguration(String hostname) throws InvalidParameterValueException;
LdapConfigurationResponse deleteConfiguration(LdapDeleteConfigurationCmd cmd) throws InvalidParameterValueException;
LdapUser getUser(final String username) throws NoLdapUserMatchingQueryException;
@Deprecated
LdapConfigurationResponse deleteConfiguration(String hostname, int port, Long domainId) throws InvalidParameterValueException;
LdapUser getUser(String username, String type, String name) throws NoLdapUserMatchingQueryException;
// TODO username is only unique withing domain scope (add domain id to call)
LdapUser getUser(final String username, Long domainId) throws NoLdapUserMatchingQueryException;
List<LdapUser> getUsers() throws NoLdapUserMatchingQueryException;
LdapUser getUser(String username, String type, String name, Long domainId) throws NoLdapUserMatchingQueryException;
List<LdapUser> getUsersInGroup(String groupName) throws NoLdapUserMatchingQueryException;
List<LdapUser> getUsers(Long domainId) throws NoLdapUserMatchingQueryException;
List<LdapUser> getUsersInGroup(String groupName, Long domainId) throws NoLdapUserMatchingQueryException;
boolean isLdapEnabled();
@ -55,7 +67,15 @@ public interface LdapManager extends PluggableService {
List<LdapUser> searchUsers(String query) throws NoLdapUserMatchingQueryException;
LinkDomainToLdapResponse linkDomainToLdap(Long domainId, String type, String name, short accountType);
LinkDomainToLdapResponse linkDomainToLdap(LinkDomainToLdapCmd cmd);
public LdapTrustMapVO getDomainLinkedToLdap(long domainId);
LdapTrustMapVO getDomainLinkedToLdap(long domainId);
List<LdapTrustMapVO> getDomainLinkage(long domainId);
LdapTrustMapVO getAccountLinkedToLdap(long domainId, long accountId);
LdapTrustMapVO getLinkedLdapGroup(long domainId, String group);
LinkAccountToLdapResponse linkAccountToLdap(LinkAccountToLdapCmd linkAccountToLdapCmd);
}

View File

@ -23,6 +23,7 @@ import java.util.List;
import javax.inject.Inject;
import javax.naming.NamingException;
import javax.naming.ldap.LdapContext;
import java.util.UUID;
import org.apache.cloudstack.api.LdapValidator;
import org.apache.cloudstack.api.command.LDAPConfigCmd;
@ -34,9 +35,11 @@ import org.apache.cloudstack.api.command.LdapImportUsersCmd;
import org.apache.cloudstack.api.command.LdapListConfigurationCmd;
import org.apache.cloudstack.api.command.LdapListUsersCmd;
import org.apache.cloudstack.api.command.LdapUserSearchCmd;
import org.apache.cloudstack.api.command.LinkAccountToLdapCmd;
import org.apache.cloudstack.api.command.LinkDomainToLdapCmd;
import org.apache.cloudstack.api.response.LdapConfigurationResponse;
import org.apache.cloudstack.api.response.LdapUserResponse;
import org.apache.cloudstack.api.response.LinkAccountToLdapResponse;
import org.apache.cloudstack.api.response.LinkDomainToLdapResponse;
import org.apache.cloudstack.ldap.dao.LdapConfigurationDao;
import org.apache.cloudstack.ldap.dao.LdapTrustMapDao;
@ -47,6 +50,9 @@ import org.springframework.stereotype.Component;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.Account;
import com.cloud.user.AccountVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.Pair;
@Component
@ -59,6 +65,9 @@ public class LdapManagerImpl implements LdapManager, LdapValidator {
@Inject
private DomainDao domainDao;
@Inject
private AccountDao accountDao;
@Inject
private LdapContextFactory _ldapContextFactory;
@ -85,17 +94,32 @@ public class LdapManagerImpl implements LdapManager, LdapValidator {
}
@Override
public LdapConfigurationResponse addConfiguration(final String hostname, final int port) throws InvalidParameterValueException {
LdapConfigurationVO configuration = _ldapConfigurationDao.findByHostname(hostname);
public LdapConfigurationResponse addConfiguration(final LdapAddConfigurationCmd cmd) throws InvalidParameterValueException {
return addConfigurationInternal(cmd.getHostname(),cmd.getPort(),cmd.getDomainId());
}
@Override // TODO make private
public LdapConfigurationResponse addConfiguration(final String hostname, int port, final Long domainId) throws InvalidParameterValueException {
return addConfigurationInternal(hostname,port,domainId);
}
private LdapConfigurationResponse addConfigurationInternal(final String hostname, int port, final Long domainId) throws InvalidParameterValueException {
// TODO evaluate what the right default should be
if(port <= 0) {
port = 389;
}
// hostname:port is unique for domain binding
LdapConfigurationVO configuration = _ldapConfigurationDao.find(hostname, port, domainId);
if (configuration == null) {
LdapContext context = null;
try {
final String providerUrl = "ldap://" + hostname + ":" + port;
context = _ldapContextFactory.createBindContext(providerUrl);
configuration = new LdapConfigurationVO(hostname, port);
context = _ldapContextFactory.createBindContext(providerUrl,domainId);
configuration = new LdapConfigurationVO(hostname, port, domainId);
_ldapConfigurationDao.persist(configuration);
s_logger.info("Added new ldap server with hostname: " + hostname);
return new LdapConfigurationResponse(hostname, port);
s_logger.info("Added new ldap server with url: " + providerUrl + (domainId == null ? "": " for domain " + domainId));
return createLdapConfigurationResponse(configuration);
} catch (NamingException | IOException e) {
s_logger.debug("NamingException while doing an LDAP bind", e);
throw new InvalidParameterValueException("Unable to bind to the given LDAP server");
@ -107,10 +131,18 @@ public class LdapManagerImpl implements LdapManager, LdapValidator {
}
}
/**
* TODO decide if the principal is good enough to get the domain id or we need to add it as parameter
* @param principal
* @param password
* @param domainId
* @return
*/
@Override
public boolean canAuthenticate(final String principal, final String password) {
public boolean canAuthenticate(final String principal, final String password, final Long domainId) {
try {
final LdapContext context = _ldapContextFactory.createUserContext(principal, password);
// TODO return the right account for this user
final LdapContext context = _ldapContextFactory.createUserContext(principal, password,domainId);
closeContext(context);
return true;
} catch (NamingException | IOException e) {
@ -132,10 +164,11 @@ public class LdapManagerImpl implements LdapManager, LdapValidator {
@Override
public LdapConfigurationResponse createLdapConfigurationResponse(final LdapConfigurationVO configuration) {
final LdapConfigurationResponse response = new LdapConfigurationResponse();
response.setHostname(configuration.getHostname());
response.setPort(configuration.getPort());
return response;
String domainUuid = null;
if(configuration.getDomainId() != null) {
domainUuid = domainDao.findById(configuration.getDomainId()).getUuid();
}
return new LdapConfigurationResponse(configuration.getHostname(), configuration.getPort(), domainUuid);
}
@Override
@ -151,14 +184,23 @@ public class LdapManagerImpl implements LdapManager, LdapValidator {
}
@Override
public LdapConfigurationResponse deleteConfiguration(final String hostname) throws InvalidParameterValueException {
final LdapConfigurationVO configuration = _ldapConfigurationDao.findByHostname(hostname);
public LdapConfigurationResponse deleteConfiguration(final LdapDeleteConfigurationCmd cmd) throws InvalidParameterValueException {
return deleteConfigurationInternal(cmd.getHostname(), cmd.getPort(), cmd.getDomainId());
}
@Override
public LdapConfigurationResponse deleteConfiguration(final String hostname, int port, Long domainId) throws InvalidParameterValueException {
return deleteConfigurationInternal(hostname, port, domainId);
}
private LdapConfigurationResponse deleteConfigurationInternal(final String hostname, int port, Long domainId) throws InvalidParameterValueException {
final LdapConfigurationVO configuration = _ldapConfigurationDao.find(hostname,port,domainId);
if (configuration == null) {
throw new InvalidParameterValueException("Cannot find configuration with hostname " + hostname);
} else {
_ldapConfigurationDao.remove(configuration.getId());
s_logger.info("Removed ldap server with hostname: " + hostname);
return new LdapConfigurationResponse(configuration.getHostname(), configuration.getPort());
s_logger.info("Removed ldap server with url: " + hostname + ':' + port + (domainId == null ? "" : " for domain id " + domainId));
return createLdapConfigurationResponse(configuration);
}
}
@ -175,17 +217,18 @@ public class LdapManagerImpl implements LdapManager, LdapValidator {
cmdList.add(LDAPConfigCmd.class);
cmdList.add(LDAPRemoveCmd.class);
cmdList.add(LinkDomainToLdapCmd.class);
cmdList.add(LinkAccountToLdapCmd.class);
return cmdList;
}
@Override
public LdapUser getUser(final String username) throws NoLdapUserMatchingQueryException {
public LdapUser getUser(final String username, Long domainId) throws NoLdapUserMatchingQueryException {
LdapContext context = null;
try {
context = _ldapContextFactory.createBindContext();
context = _ldapContextFactory.createBindContext(domainId);
final String escapedUsername = LdapUtils.escapeLDAPSearchFilter(username);
return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider()).getUser(escapedUsername, context);
return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider(null)).getUser(escapedUsername, context, domainId);
} catch (NamingException | IOException e) {
s_logger.debug("ldap Exception: ",e);
@ -196,26 +239,26 @@ public class LdapManagerImpl implements LdapManager, LdapValidator {
}
@Override
public LdapUser getUser(final String username, final String type, final String name) throws NoLdapUserMatchingQueryException {
public LdapUser getUser(final String username, final String type, final String name, Long domainId) throws NoLdapUserMatchingQueryException {
LdapContext context = null;
try {
context = _ldapContextFactory.createBindContext();
context = _ldapContextFactory.createBindContext(domainId);
final String escapedUsername = LdapUtils.escapeLDAPSearchFilter(username);
return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider()).getUser(escapedUsername, type, name, context);
return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider(null)).getUser(escapedUsername, type, name, context, domainId);
} catch (NamingException | IOException e) {
s_logger.debug("ldap Exception: ",e);
throw new NoLdapUserMatchingQueryException("No Ldap User found for username: "+username + "name: " + name + "of type: " + type);
throw new NoLdapUserMatchingQueryException("No Ldap User found for username: "+username + " in group: " + name + " of type: " + type);
} finally {
closeContext(context);
}
}
@Override
public List<LdapUser> getUsers() throws NoLdapUserMatchingQueryException {
public List<LdapUser> getUsers(Long domainId) throws NoLdapUserMatchingQueryException {
LdapContext context = null;
try {
context = _ldapContextFactory.createBindContext();
return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider()).getUsers(context);
context = _ldapContextFactory.createBindContext(domainId);
return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider(domainId)).getUsers(context, domainId);
} catch (NamingException | IOException e) {
s_logger.debug("ldap Exception: ",e);
throw new NoLdapUserMatchingQueryException("*");
@ -225,11 +268,11 @@ public class LdapManagerImpl implements LdapManager, LdapValidator {
}
@Override
public List<LdapUser> getUsersInGroup(String groupName) throws NoLdapUserMatchingQueryException {
public List<LdapUser> getUsersInGroup(String groupName, Long domainId) throws NoLdapUserMatchingQueryException {
LdapContext context = null;
try {
context = _ldapContextFactory.createBindContext();
return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider()).getUsersInGroup(groupName, context);
context = _ldapContextFactory.createBindContext(domainId);
return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider(domainId)).getUsersInGroup(groupName, context, domainId);
} catch (NamingException | IOException e) {
s_logger.debug("ldap NamingException: ",e);
throw new NoLdapUserMatchingQueryException("groupName=" + groupName);
@ -247,7 +290,8 @@ public class LdapManagerImpl implements LdapManager, LdapValidator {
public Pair<List<? extends LdapConfigurationVO>, Integer> listConfigurations(final LdapListConfigurationCmd cmd) {
final String hostname = cmd.getHostname();
final int port = cmd.getPort();
final Pair<List<LdapConfigurationVO>, Integer> result = _ldapConfigurationDao.searchConfigurations(hostname, port);
final Long domainId = cmd.getDomainId();
final Pair<List<LdapConfigurationVO>, Integer> result = _ldapConfigurationDao.searchConfigurations(hostname, port, domainId);
return new Pair<List<? extends LdapConfigurationVO>, Integer>(result.first(), result.second());
}
@ -255,9 +299,10 @@ public class LdapManagerImpl implements LdapManager, LdapValidator {
public List<LdapUser> searchUsers(final String username) throws NoLdapUserMatchingQueryException {
LdapContext context = null;
try {
context = _ldapContextFactory.createBindContext();
// TODO search users per domain (only?)
context = _ldapContextFactory.createBindContext(null);
final String escapedUsername = LdapUtils.escapeLDAPSearchFilter(username);
return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider()).getUsers("*" + escapedUsername + "*", context);
return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider(null)).getUsers("*" + escapedUsername + "*", context, null);
} catch (NamingException | IOException e) {
s_logger.debug("ldap Exception: ",e);
throw new NoLdapUserMatchingQueryException(username);
@ -267,14 +312,20 @@ public class LdapManagerImpl implements LdapManager, LdapValidator {
}
@Override
public LinkDomainToLdapResponse linkDomainToLdap(Long domainId, String type, String name, short accountType) {
public LinkDomainToLdapResponse linkDomainToLdap(LinkDomainToLdapCmd cmd) {
Validate.isTrue(_ldapConfiguration.getBaseDn(cmd.getDomainId()) == null, "can not configure an ldap server and an ldap group/ou to a domain");
Validate.notEmpty(cmd.getLdapDomain(), "ldapDomain cannot be empty, please supply a GROUP or OU name");
return linkDomainToLdap(cmd.getDomainId(),cmd.getType(),cmd.getLdapDomain(),cmd.getAccountType());
}
private LinkDomainToLdapResponse linkDomainToLdap(Long domainId, String type, String name, short accountType) {
Validate.notNull(type, "type cannot be null. It should either be GROUP or OU");
Validate.notNull(domainId, "domainId cannot be null.");
Validate.notEmpty(name, "GROUP or OU name cannot be empty");
//Account type should be 0 or 2. check the constants in com.cloud.user.Account
Validate.isTrue(accountType==0 || accountType==2, "accountype should be either 0(normal user) or 2(domain admin)");
LinkType linkType = LdapManager.LinkType.valueOf(type.toUpperCase());
LdapTrustMapVO vo = _ldapTrustMapDao.persist(new LdapTrustMapVO(domainId, linkType, name, accountType));
LdapTrustMapVO vo = _ldapTrustMapDao.persist(new LdapTrustMapVO(domainId, linkType, name, accountType, 0));
DomainVO domain = domainDao.findById(vo.getDomainId());
String domainUuid = "<unknown>";
if (domain == null) {
@ -290,4 +341,46 @@ public class LdapManagerImpl implements LdapManager, LdapValidator {
public LdapTrustMapVO getDomainLinkedToLdap(long domainId){
return _ldapTrustMapDao.findByDomainId(domainId);
}
@Override
public List<LdapTrustMapVO> getDomainLinkage(long domainId){
return _ldapTrustMapDao.searchByDomainId(domainId);
}
public LdapTrustMapVO getAccountLinkedToLdap(long domainId, long accountId){
return _ldapTrustMapDao.findByAccount(domainId, accountId);
}
@Override
public LdapTrustMapVO getLinkedLdapGroup(long domainId, String group) {
return _ldapTrustMapDao.findGroupInDomain(domainId, group);
}
@Override public LinkAccountToLdapResponse linkAccountToLdap(LinkAccountToLdapCmd cmd) {
Validate.notNull(_ldapConfiguration.getBaseDn(cmd.getDomainId()), "can not configure an ldap server and an ldap group/ou to a domain");
Validate.notNull(cmd.getDomainId(), "domainId cannot be null.");
Validate.notEmpty(cmd.getAccountName(), "accountName cannot be empty.");
Validate.notEmpty(cmd.getLdapDomain(), "ldapDomain cannot be empty, please supply a GROUP or OU name");
Validate.notNull(cmd.getType(), "type cannot be null. It should either be GROUP or OU");
Validate.notEmpty(cmd.getLdapDomain(), "GROUP or OU name cannot be empty");
LinkType linkType = LdapManager.LinkType.valueOf(cmd.getType().toUpperCase());
Account account = accountDao.findActiveAccount(cmd.getAccountName(),cmd.getDomainId());
if (account == null) {
account = new AccountVO(cmd.getAccountName(), cmd.getDomainId(), null, cmd.getAccountType(), UUID.randomUUID().toString());
accountDao.persist((AccountVO)account);
}
Long accountId = account.getAccountId();
LdapTrustMapVO vo = _ldapTrustMapDao.persist(new LdapTrustMapVO(cmd.getDomainId(), linkType, cmd.getLdapDomain(), cmd.getAccountType(), accountId));
DomainVO domain = domainDao.findById(vo.getDomainId());
String domainUuid = "<unknown>";
if (domain == null) {
s_logger.error("no domain in database for id " + vo.getDomainId());
} else {
domainUuid = domain.getUuid();
}
LinkAccountToLdapResponse response = new LinkAccountToLdapResponse(domainUuid, vo.getType().toString(), vo.getName(), vo.getAccountType(), account.getUuid(), cmd.getAccountName());
return response;
}
}

View File

@ -45,6 +45,9 @@ public class LdapTrustMapVO implements InternalIdentity {
@Column(name = "domain_id")
private long domainId;
@Column(name = "account_id")
private long accountId;
@Column(name = "account_type")
private short accountType;
@ -52,11 +55,12 @@ public class LdapTrustMapVO implements InternalIdentity {
public LdapTrustMapVO() {
}
public LdapTrustMapVO(long domainId, LdapManager.LinkType type, String name, short accountType) {
public LdapTrustMapVO(long domainId, LdapManager.LinkType type, String name, short accountType, long accountId) {
this.domainId = domainId;
this.type = type;
this.name = name;
this.accountType = accountType;
this.accountId = accountId;
}
@Override
@ -80,6 +84,10 @@ public class LdapTrustMapVO implements InternalIdentity {
return accountType;
}
public long getAccountId() {
return accountId;
}
@Override
public boolean equals(Object o) {
if (this == o) {
@ -94,6 +102,9 @@ public class LdapTrustMapVO implements InternalIdentity {
if (domainId != that.domainId) {
return false;
}
if (accountId != that.accountId) {
return false;
}
if (accountType != that.accountType) {
return false;
}
@ -109,6 +120,7 @@ public class LdapTrustMapVO implements InternalIdentity {
int result = type.hashCode();
result = 31 * result + name.hashCode();
result = 31 * result + (int) (domainId ^ (domainId >>> 32));
result = 31 * result + (int) (accountId ^ (accountId >>> 32));
result = 31 * result + (int) accountType;
return result;
}

View File

@ -16,6 +16,9 @@
// under the License.
package org.apache.cloudstack.ldap;
import java.util.ArrayList;
import java.util.List;
public class LdapUser implements Comparable<LdapUser> {
private final String email;
private final String principal;
@ -24,8 +27,10 @@ public class LdapUser implements Comparable<LdapUser> {
private final String username;
private final String domain;
private final boolean disabled;
private List<String> memberships;
public LdapUser(final String username, final String email, final String firstname, final String lastname, final String principal, String domain, boolean disabled) {
public LdapUser(final String username, final String email, final String firstname, final String lastname, final String principal, String domain, boolean disabled,
List<String> memberships) {
this.username = username;
this.email = email;
this.firstname = firstname;
@ -33,6 +38,7 @@ public class LdapUser implements Comparable<LdapUser> {
this.principal = principal;
this.domain = domain;
this.disabled = disabled;
this.memberships = memberships == null ? new ArrayList<>() : memberships;
}
@Override
@ -80,6 +86,9 @@ public class LdapUser implements Comparable<LdapUser> {
return disabled;
}
public List<String> getMemberships() {
return memberships;
}
@Override
public int hashCode() {

View File

@ -30,17 +30,17 @@ public interface LdapUserManager {
MICROSOFTAD, OPENLDAP;
}
public LdapUser getUser(final String username, final LdapContext context) throws NamingException, IOException;
public LdapUser getUser(final String username, final LdapContext context, Long domainId) throws NamingException, IOException;
public LdapUser getUser(final String username, final String type, final String name, final LdapContext context) throws NamingException, IOException;
public LdapUser getUser(final String username, final String type, final String name, final LdapContext context, Long domainId) throws NamingException, IOException;
public List<LdapUser> getUsers(final LdapContext context) throws NamingException, IOException;
public List<LdapUser> getUsers(final LdapContext context, Long domainId) throws NamingException, IOException;
public List<LdapUser> getUsers(final String username, final LdapContext context) throws NamingException, IOException;
public List<LdapUser> getUsers(final String username, final LdapContext context, Long domainId) throws NamingException, IOException;
public List<LdapUser> getUsersInGroup(String groupName, LdapContext context) throws NamingException;
public List<LdapUser> getUsersInGroup(String groupName, LdapContext context, Long domainId) throws NamingException;
public List<LdapUser> searchUsers(final LdapContext context) throws NamingException, IOException;
public List<LdapUser> searchUsers(final LdapContext context, Long domainId) throws NamingException, IOException;
public List<LdapUser> searchUsers(final String username, final LdapContext context) throws NamingException, IOException;
public List<LdapUser> searchUsers(final String username, final LdapContext context, Long domainId) throws NamingException, IOException;
}

View File

@ -16,9 +16,12 @@
// under the License.
package org.apache.cloudstack.ldap;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import java.util.ArrayList;
import java.util.List;
public final class LdapUtils {
public static String escapeLDAPSearchFilter(final String filter) {
@ -56,6 +59,18 @@ public final class LdapUtils {
return null;
}
public static List<String> getAttributeValues(final Attributes attributes, final String attributeName) throws NamingException {
ArrayList<String> memberships = new ArrayList<>();
final Attribute attribute = attributes.get(attributeName);
if (attribute != null) {
NamingEnumeration<?> values = attribute.getAll();
while(values.hasMore()) {
memberships.add(String.valueOf(values.next()));
}
}
return memberships;
}
private LdapUtils() {
}
}

View File

@ -50,41 +50,46 @@ public class OpenLdapUserManagerImpl implements LdapUserManager {
_ldapConfiguration = ldapConfiguration;
}
protected LdapUser createUser(final SearchResult result) throws NamingException {
protected LdapUser createUser(final SearchResult result, Long domainId) throws NamingException {
final Attributes attributes = result.getAttributes();
final String username = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getUsernameAttribute());
final String email = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getEmailAttribute());
final String firstname = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getFirstnameAttribute());
final String lastname = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getLastnameAttribute());
final String username = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getUsernameAttribute(domainId));
final String email = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getEmailAttribute(domainId));
final String firstname = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getFirstnameAttribute(domainId));
final String lastname = LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getLastnameAttribute(domainId));
final String principal = result.getNameInNamespace();
final List<String> memberships = LdapUtils.getAttributeValues(attributes, _ldapConfiguration.getUserMemberOfAttribute(domainId));
String domain = principal.replace("cn=" + LdapUtils.getAttributeValue(attributes, _ldapConfiguration.getCommonNameAttribute()) + ",", "");
domain = domain.replace("," + _ldapConfiguration.getBaseDn(), "");
domain = domain.replace("," + _ldapConfiguration.getBaseDn(domainId), "");
domain = domain.replace("ou=", "");
boolean disabled = isUserDisabled(result);
return new LdapUser(username, email, firstname, lastname, principal, domain, disabled);
return new LdapUser(username, email, firstname, lastname, principal, domain, disabled, memberships);
}
private String generateSearchFilter(final String username) {
private String generateSearchFilter(final String username, Long domainId) {
final StringBuilder userObjectFilter = new StringBuilder();
userObjectFilter.append("(objectClass=");
userObjectFilter.append(_ldapConfiguration.getUserObject());
userObjectFilter.append(_ldapConfiguration.getUserObject(domainId));
userObjectFilter.append(")");
final StringBuilder usernameFilter = new StringBuilder();
usernameFilter.append("(");
usernameFilter.append(_ldapConfiguration.getUsernameAttribute());
usernameFilter.append(_ldapConfiguration.getUsernameAttribute(domainId));
usernameFilter.append("=");
usernameFilter.append((username == null ? "*" : username));
usernameFilter.append(")");
final StringBuilder memberOfFilter = new StringBuilder();
if (_ldapConfiguration.getSearchGroupPrinciple() != null) {
memberOfFilter.append("(memberof=");
memberOfFilter.append(_ldapConfiguration.getSearchGroupPrinciple());
if (_ldapConfiguration.getSearchGroupPrinciple(domainId) != null) {
if(s_logger.isDebugEnabled()) {
s_logger.debug("adding search filter for '" + _ldapConfiguration.getSearchGroupPrinciple(domainId) +
"', using " + _ldapConfiguration.getUserMemberOfAttribute(domainId));
}
memberOfFilter.append("(" + _ldapConfiguration.getUserMemberOfAttribute(domainId) + "=");
memberOfFilter.append(_ldapConfiguration.getSearchGroupPrinciple(domainId));
memberOfFilter.append(")");
}
@ -98,10 +103,10 @@ public class OpenLdapUserManagerImpl implements LdapUserManager {
return result.toString();
}
private String generateGroupSearchFilter(final String groupName) {
private String generateGroupSearchFilter(final String groupName, Long domainId) {
final StringBuilder groupObjectFilter = new StringBuilder();
groupObjectFilter.append("(objectClass=");
groupObjectFilter.append(_ldapConfiguration.getGroupObject());
groupObjectFilter.append(_ldapConfiguration.getGroupObject(domainId));
groupObjectFilter.append(")");
final StringBuilder groupNameFilter = new StringBuilder();
@ -121,8 +126,8 @@ public class OpenLdapUserManagerImpl implements LdapUserManager {
}
@Override
public LdapUser getUser(final String username, final LdapContext context) throws NamingException, IOException {
List<LdapUser> result = searchUsers(username, context);
public LdapUser getUser(final String username, final LdapContext context, Long domainId) throws NamingException, IOException {
List<LdapUser> result = searchUsers(username, context, domainId);
if (result!= null && result.size() == 1) {
return result.get(0);
} else {
@ -131,29 +136,29 @@ public class OpenLdapUserManagerImpl implements LdapUserManager {
}
@Override
public LdapUser getUser(final String username, final String type, final String name, final LdapContext context) throws NamingException, IOException {
public LdapUser getUser(final String username, final String type, final String name, final LdapContext context, Long domainId) throws NamingException, IOException {
String basedn;
if("OU".equals(type)) {
basedn = name;
} else {
basedn = _ldapConfiguration.getBaseDn();
basedn = _ldapConfiguration.getBaseDn(domainId);
}
final StringBuilder userObjectFilter = new StringBuilder();
userObjectFilter.append("(objectClass=");
userObjectFilter.append(_ldapConfiguration.getUserObject());
userObjectFilter.append(_ldapConfiguration.getUserObject(domainId));
userObjectFilter.append(")");
final StringBuilder usernameFilter = new StringBuilder();
usernameFilter.append("(");
usernameFilter.append(_ldapConfiguration.getUsernameAttribute());
usernameFilter.append(_ldapConfiguration.getUsernameAttribute(domainId));
usernameFilter.append("=");
usernameFilter.append((username == null ? "*" : username));
usernameFilter.append(")");
final StringBuilder memberOfFilter = new StringBuilder();
if ("GROUP".equals(type)) {
memberOfFilter.append("(").append(getMemberOfAttribute()).append("=");
memberOfFilter.append("(").append(getMemberOfAttribute(domainId)).append("=");
memberOfFilter.append(name);
memberOfFilter.append(")");
}
@ -165,21 +170,21 @@ public class OpenLdapUserManagerImpl implements LdapUserManager {
searchQuery.append(memberOfFilter);
searchQuery.append(")");
return searchUser(basedn, searchQuery.toString(), context);
return searchUser(basedn, searchQuery.toString(), context, domainId);
}
protected String getMemberOfAttribute() {
return "memberof";
protected String getMemberOfAttribute(final Long domainId) {
return _ldapConfiguration.getUserMemberOfAttribute(domainId);
}
@Override
public List<LdapUser> getUsers(final LdapContext context) throws NamingException, IOException {
return getUsers(null, context);
public List<LdapUser> getUsers(final LdapContext context, Long domainId) throws NamingException, IOException {
return getUsers(null, context, domainId);
}
@Override
public List<LdapUser> getUsers(final String username, final LdapContext context) throws NamingException, IOException {
List<LdapUser> users = searchUsers(username, context);
public List<LdapUser> getUsers(final String username, final LdapContext context, Long domainId) throws NamingException, IOException {
List<LdapUser> users = searchUsers(username, context, domainId);
if (CollectionUtils.isNotEmpty(users)) {
Collections.sort(users);
@ -188,13 +193,13 @@ public class OpenLdapUserManagerImpl implements LdapUserManager {
}
@Override
public List<LdapUser> getUsersInGroup(String groupName, LdapContext context) throws NamingException {
String attributeName = _ldapConfiguration.getGroupUniqueMemeberAttribute();
public List<LdapUser> getUsersInGroup(String groupName, LdapContext context, Long domainId) throws NamingException {
String attributeName = _ldapConfiguration.getGroupUniqueMemberAttribute(domainId);
final SearchControls controls = new SearchControls();
controls.setSearchScope(_ldapConfiguration.getScope());
controls.setReturningAttributes(new String[] {attributeName});
NamingEnumeration<SearchResult> result = context.search(_ldapConfiguration.getBaseDn(), generateGroupSearchFilter(groupName), controls);
NamingEnumeration<SearchResult> result = context.search(_ldapConfiguration.getBaseDn(domainId), generateGroupSearchFilter(groupName, domainId), controls);
final List<LdapUser> users = new ArrayList<LdapUser>();
//Expecting only one result which has all the users
@ -205,7 +210,7 @@ public class OpenLdapUserManagerImpl implements LdapUserManager {
while (values.hasMoreElements()) {
String userdn = String.valueOf(values.nextElement());
try{
users.add(getUserForDn(userdn, context));
users.add(getUserForDn(userdn, context, domainId));
} catch (NamingException e){
s_logger.info("Userdn: " + userdn + " Not Found:: Exception message: " + e.getMessage());
}
@ -217,39 +222,42 @@ public class OpenLdapUserManagerImpl implements LdapUserManager {
return users;
}
private LdapUser getUserForDn(String userdn, LdapContext context) throws NamingException {
private LdapUser getUserForDn(String userdn, LdapContext context, Long domainId) throws NamingException {
final SearchControls controls = new SearchControls();
controls.setSearchScope(_ldapConfiguration.getScope());
controls.setReturningAttributes(_ldapConfiguration.getReturnAttributes());
controls.setReturningAttributes(_ldapConfiguration.getReturnAttributes(domainId));
NamingEnumeration<SearchResult> result = context.search(userdn, "(objectClass=" + _ldapConfiguration.getUserObject() + ")", controls);
NamingEnumeration<SearchResult> result = context.search(userdn, "(objectClass=" + _ldapConfiguration.getUserObject(domainId) + ")", controls);
if (result.hasMoreElements()) {
return createUser(result.nextElement());
return createUser(result.nextElement(), domainId);
} else {
throw new NamingException("No user found for dn " + userdn);
}
}
@Override
public List<LdapUser> searchUsers(final LdapContext context) throws NamingException, IOException {
return searchUsers(null, context);
public List<LdapUser> searchUsers(final LdapContext context, Long domainId) throws NamingException, IOException {
return searchUsers(null, context, domainId);
}
protected boolean isUserDisabled(SearchResult result) throws NamingException {
return false;
}
public LdapUser searchUser(final String basedn, final String searchString, final LdapContext context) throws NamingException, IOException {
public LdapUser searchUser(final String basedn, final String searchString, final LdapContext context, Long domainId) throws NamingException, IOException {
final SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(_ldapConfiguration.getScope());
searchControls.setReturningAttributes(_ldapConfiguration.getReturnAttributes());
searchControls.setReturningAttributes(_ldapConfiguration.getReturnAttributes(domainId));
NamingEnumeration<SearchResult> results = context.search(basedn, searchString, searchControls);
if(s_logger.isDebugEnabled()) {
s_logger.debug("searching user(s) with filter: \"" + searchString + "\"");
}
final List<LdapUser> users = new ArrayList<LdapUser>();
while (results.hasMoreElements()) {
final SearchResult result = results.nextElement();
users.add(createUser(result));
users.add(createUser(result, domainId));
}
if (users.size() == 1) {
@ -260,28 +268,28 @@ public class OpenLdapUserManagerImpl implements LdapUserManager {
}
@Override
public List<LdapUser> searchUsers(final String username, final LdapContext context) throws NamingException, IOException {
public List<LdapUser> searchUsers(final String username, final LdapContext context, Long domainId) throws NamingException, IOException {
final SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(_ldapConfiguration.getScope());
searchControls.setReturningAttributes(_ldapConfiguration.getReturnAttributes());
searchControls.setReturningAttributes(_ldapConfiguration.getReturnAttributes(domainId));
String basedn = _ldapConfiguration.getBaseDn();
String basedn = _ldapConfiguration.getBaseDn(domainId);
if (StringUtils.isBlank(basedn)) {
throw new IllegalArgumentException("ldap basedn is not configured");
}
byte[] cookie = null;
int pageSize = _ldapConfiguration.getLdapPageSize();
int pageSize = _ldapConfiguration.getLdapPageSize(domainId);
context.setRequestControls(new Control[]{new PagedResultsControl(pageSize, Control.NONCRITICAL)});
final List<LdapUser> users = new ArrayList<LdapUser>();
NamingEnumeration<SearchResult> results;
do {
results = context.search(basedn, generateSearchFilter(username), searchControls);
results = context.search(basedn, generateSearchFilter(username, domainId), searchControls);
while (results.hasMoreElements()) {
final SearchResult result = results.nextElement();
if (!isUserDisabled(result)) {
users.add(createUser(result));
users.add(createUser(result, domainId));
}
}
Control[] contextControls = context.getResponseControls();

View File

@ -23,8 +23,19 @@ import org.apache.cloudstack.ldap.LdapConfigurationVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.GenericDao;
/**
* TODO the domain value null now searches for that specifically and there is no way to search for all domains
*/
public interface LdapConfigurationDao extends GenericDao<LdapConfigurationVO, Long> {
/**
* @deprecated there might well be more then one ldap implementation on a host and or a double binding of several domains
* @param hostname
* @return
*/
@Deprecated
LdapConfigurationVO findByHostname(String hostname);
Pair<List<LdapConfigurationVO>, Integer> searchConfigurations(String hostname, int port);
LdapConfigurationVO find(String hostname, int port, Long domainId);
Pair<List<LdapConfigurationVO>, Integer> searchConfigurations(String hostname, int port, Long domainId);
}

View File

@ -32,7 +32,8 @@ import com.cloud.utils.db.SearchCriteria.Op;
@Component
public class LdapConfigurationDaoImpl extends GenericDaoBase<LdapConfigurationVO, Long> implements LdapConfigurationDao {
private final SearchBuilder<LdapConfigurationVO> hostnameSearch;
private final SearchBuilder<LdapConfigurationVO> listAllConfigurationsSearch;
private final SearchBuilder<LdapConfigurationVO> listGlobalConfigurationsSearch;
private final SearchBuilder<LdapConfigurationVO> listDomainConfigurationsSearch;
public LdapConfigurationDaoImpl() {
super();
@ -40,10 +41,16 @@ public class LdapConfigurationDaoImpl extends GenericDaoBase<LdapConfigurationVO
hostnameSearch.and("hostname", hostnameSearch.entity().getHostname(), SearchCriteria.Op.EQ);
hostnameSearch.done();
listAllConfigurationsSearch = createSearchBuilder();
listAllConfigurationsSearch.and("hostname", listAllConfigurationsSearch.entity().getHostname(), Op.EQ);
listAllConfigurationsSearch.and("port", listAllConfigurationsSearch.entity().getPort(), Op.EQ);
listAllConfigurationsSearch.done();
listGlobalConfigurationsSearch = createSearchBuilder();
listGlobalConfigurationsSearch.and("hostname", listGlobalConfigurationsSearch.entity().getHostname(), Op.EQ);
listGlobalConfigurationsSearch.and("port", listGlobalConfigurationsSearch.entity().getPort(), Op.EQ);
listGlobalConfigurationsSearch.and("domain_id", listGlobalConfigurationsSearch.entity().getDomainId(),SearchCriteria.Op.NULL);
listGlobalConfigurationsSearch.done();
listDomainConfigurationsSearch = createSearchBuilder();
listDomainConfigurationsSearch.and("hostname", listDomainConfigurationsSearch.entity().getHostname(), Op.EQ);
listDomainConfigurationsSearch.and("port", listDomainConfigurationsSearch.entity().getPort(), Op.EQ);
listDomainConfigurationsSearch.and("domain_id", listDomainConfigurationsSearch.entity().getDomainId(), Op.EQ);
listDomainConfigurationsSearch.done();
}
@Override
@ -54,11 +61,31 @@ public class LdapConfigurationDaoImpl extends GenericDaoBase<LdapConfigurationVO
}
@Override
public Pair<List<LdapConfigurationVO>, Integer> searchConfigurations(final String hostname, final int port) {
final SearchCriteria<LdapConfigurationVO> sc = listAllConfigurationsSearch.create();
public LdapConfigurationVO find(String hostname, int port, Long domainId) {
SearchCriteria<LdapConfigurationVO> sc = getSearchCriteria(hostname, port, domainId);
return findOneBy(sc);
}
@Override
public Pair<List<LdapConfigurationVO>, Integer> searchConfigurations(final String hostname, final int port, final Long domainId) {
SearchCriteria<LdapConfigurationVO> sc = getSearchCriteria(hostname, port, domainId);
return searchAndCount(sc, null);
}
private SearchCriteria<LdapConfigurationVO> getSearchCriteria(String hostname, int port, Long domainId) {
SearchCriteria<LdapConfigurationVO> sc;
if (domainId == null) {
sc = listDomainConfigurationsSearch.create();
} else {
sc = listDomainConfigurationsSearch.create();
sc.setParameters("domain_id", domainId);
}
if (hostname != null) {
sc.setParameters("hostname", hostname);
}
return searchAndCount(sc, null);
if (port > 0) {
sc.setParameters("port", port);
}
return sc;
}
}

View File

@ -22,6 +22,11 @@ import org.apache.cloudstack.ldap.LdapTrustMapVO;
import com.cloud.utils.db.GenericDao;
import java.util.List;
public interface LdapTrustMapDao extends GenericDao<LdapTrustMapVO, Long> {
LdapTrustMapVO findByDomainId(long domainId);
LdapTrustMapVO findByAccount(long domainId, Long accountId);
LdapTrustMapVO findGroupInDomain(long domainId, String group);
List<LdapTrustMapVO> searchByDomainId(long domainId);
}

View File

@ -26,21 +26,55 @@ import org.springframework.stereotype.Component;
import com.cloud.utils.db.GenericDaoBase;
import java.util.List;
@Component
public class LdapTrustMapDaoImpl extends GenericDaoBase<LdapTrustMapVO, Long> implements LdapTrustMapDao {
private final SearchBuilder<LdapTrustMapVO> domainIdSearch;
private final SearchBuilder<LdapTrustMapVO> groupSearch;
public LdapTrustMapDaoImpl() {
super();
domainIdSearch = createSearchBuilder();
domainIdSearch.and("domainId", domainIdSearch.entity().getDomainId(), SearchCriteria.Op.EQ);
domainIdSearch.and("account_id", domainIdSearch.entity().getAccountId(),SearchCriteria.Op.EQ);
domainIdSearch.done();
groupSearch = createSearchBuilder();
groupSearch.and("domainId", groupSearch.entity().getDomainId(), SearchCriteria.Op.EQ);
groupSearch.and("name", groupSearch.entity().getName(),SearchCriteria.Op.EQ);
groupSearch.done();
}
@Override
public LdapTrustMapVO findByDomainId(long domainId) {
final SearchCriteria<LdapTrustMapVO> sc = domainIdSearch.create();
sc.setParameters("domainId", domainId);
sc.setParameters("account_id", 0);
return findOneBy(sc);
}
@Override
public LdapTrustMapVO findByAccount(long domainId, Long accountId) {
final SearchCriteria<LdapTrustMapVO> sc = domainIdSearch.create();
sc.setParameters("domainId", domainId);
sc.setParameters("account_id", accountId);
return findOneBy(sc);
}
@Override
public LdapTrustMapVO findGroupInDomain(long domainId, String group){
final SearchCriteria<LdapTrustMapVO> sc = groupSearch.create();
sc.setParameters("domainId", domainId);
sc.setParameters("name", group);
return findOneBy(sc);
}
@Override
public List<LdapTrustMapVO> searchByDomainId(long domainId) {
final SearchCriteria<LdapTrustMapVO> sc = domainIdSearch.create();
sc.setParameters("domainId", domainId);
return search(sc,null);
}
}

View File

@ -69,13 +69,13 @@ class ADLdapUserManagerImplSpec extends spock.lang.Specification {
def "test getUsersInGroup null group"() {
ldapConfiguration.getScope() >> SearchControls.SUBTREE_SCOPE
ldapConfiguration.getReturnAttributes() >> ["username", "firstname", "lastname", "email"]
ldapConfiguration.getBaseDn() >>> [null, null, "DC=cloud,DC=citrix,DC=com"]
ldapConfiguration.getReturnAttributes(null) >> ["username", "firstname", "lastname", "email"]
ldapConfiguration.getBaseDn(null) >>> [null, null, "DC=cloud,DC=citrix,DC=com"]
LdapContext context = Mock(LdapContext);
when:
def result = adLdapUserManager.getUsersInGroup(group, context)
def result = adLdapUserManager.getUsersInGroup(group, context,null)
then:
thrown(IllegalArgumentException)
where:

View File

@ -49,8 +49,8 @@ class LdapAuthenticatorSpec extends spock.lang.Specification {
def ldapUser = Mock(LdapUser)
ldapUser.isDisabled() >> false
ldapManager.isLdapEnabled() >> true
ldapManager.getUser("rmurphy") >> ldapUser
ldapManager.canAuthenticate(_, _) >> false
ldapManager.getUser("rmurphy", null) >> ldapUser
ldapManager.canAuthenticate(_, _, _) >> false
UserAccountDao userAccountDao = Mock(UserAccountDao)
userAccountDao.getUserAccount(_, _) >> new UserAccountVO()
@ -84,8 +84,8 @@ class LdapAuthenticatorSpec extends spock.lang.Specification {
def ldapUser = Mock(LdapUser)
ldapUser.isDisabled() >> false
ldapManager.isLdapEnabled() >> true
ldapManager.canAuthenticate(_, _) >> true
ldapManager.getUser("rmurphy") >> ldapUser
ldapManager.canAuthenticate(_, _, _) >> true
ldapManager.getUser("rmurphy", null) >> ldapUser
UserAccountDao userAccountDao = Mock(UserAccountDao)
userAccountDao.getUserAccount(_, _) >> new UserAccountVO()
@ -144,7 +144,7 @@ class LdapAuthenticatorSpec extends spock.lang.Specification {
userAccountDao.getUserAccount(username, domainId) >> userAccount
userAccount.getId() >> 1
ldapManager.getDomainLinkedToLdap(domainId) >> new LdapTrustMapVO(domainId, type, name, (short)2)
ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", true)
ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", true, null)
//user should be disabled in cloudstack
accountManager.disableUser(1) >> userAccount
@ -173,8 +173,8 @@ class LdapAuthenticatorSpec extends spock.lang.Specification {
ldapManager.isLdapEnabled() >> true
userAccountDao.getUserAccount(username, domainId) >> null
ldapManager.getDomainLinkedToLdap(domainId) >> new LdapTrustMapVO(domainId, type, name, (short)0)
ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false)
ldapManager.canAuthenticate(_,_) >> true
ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false, null)
ldapManager.canAuthenticate(_, _, _) >> true
//user should be created in cloudstack
accountManager.createUserAccount(username, "", "firstname", "lastname", "email", null, username, (short) 2, domainId, username, null, _, _, User.Source.LDAP) >> Mock(UserAccount)
@ -206,8 +206,8 @@ class LdapAuthenticatorSpec extends spock.lang.Specification {
userAccount.getId() >> 1
userAccount.getState() >> Account.State.disabled.toString()
ldapManager.getDomainLinkedToLdap(domainId) >> new LdapTrustMapVO(domainId, type, name, (short)2)
ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false)
ldapManager.canAuthenticate(_,_) >> true
ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false, null)
ldapManager.canAuthenticate(_, _, _) >> true
//user should be enabled in cloudstack if disabled
accountManager.enableUser(1) >> userAccount
@ -237,8 +237,8 @@ class LdapAuthenticatorSpec extends spock.lang.Specification {
UserAccount userAccount = Mock(UserAccount)
userAccountDao.getUserAccount(username, domainId) >> userAccount
ldapManager.getDomainLinkedToLdap(domainId) >> new LdapTrustMapVO(domainId, type, name, (short)2)
ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false)
ldapManager.canAuthenticate(_,_) >> false
ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false, null)
ldapManager.canAuthenticate(_, _, _) >> false
when:
Pair<Boolean, UserAuthenticator.ActionOnFailedAuthentication> result = ldapAuthenticator.authenticate(username, "password", domainId, null)

View File

@ -22,8 +22,8 @@ class LdapConfigurationDaoImplSpec extends spock.lang.Specification {
def "Test setting up of a LdapConfigurationDao"() {
given: "We have an LdapConfigurationDao implementation"
def ldapConfigurationDaoImpl = new LdapConfigurationDaoImpl();
expect: "that hostnameSearch and listAllConfigurationsSearch is configured"
expect: "that hostnameSearch and listDomainConfigurationsSearch is configured"
ldapConfigurationDaoImpl.hostnameSearch != null;
ldapConfigurationDaoImpl.listAllConfigurationsSearch != null
ldapConfigurationDaoImpl.listDomainConfigurationsSearch != null
}
}

View File

@ -19,55 +19,26 @@ package groovy.org.apache.cloudstack.ldap
import org.apache.cloudstack.framework.config.ConfigKey
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import com.cloud.utils.Pair
import org.apache.cloudstack.api.ServerApiException
import org.apache.cloudstack.framework.config.impl.ConfigDepotImpl
import org.apache.cloudstack.framework.config.impl.ConfigurationVO
import org.apache.cloudstack.ldap.LdapConfiguration
import org.apache.cloudstack.ldap.LdapConfigurationVO
import org.apache.cloudstack.ldap.LdapManager
import org.apache.cloudstack.ldap.LdapUserManager
import org.apache.cloudstack.ldap.dao.LdapConfigurationDao
import org.apache.cxf.common.util.StringUtils
import javax.naming.directory.SearchControls
class LdapConfigurationSpec extends spock.lang.Specification {
def "Test that getAuthentication returns none"() {
given: "We have a ConfigDao, LdapManager and LdapConfiguration"
def configDao = Mock(ConfigurationDao)
def ldapConfigurationDao = Mock(LdapConfigurationDao)
def ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao)
def ldapConfiguration = new LdapConfiguration(ldapConfigurationDao)
when: "Get authentication is called"
String authentication = ldapConfiguration.getAuthentication()
then: "none should be returned"
authentication == "none"
}
def "Test that getAuthentication returns simple"() {
given: "We have a configDao, LdapManager and LdapConfiguration with bind principle and password set"
def configDao = Mock(ConfigurationDao)
def ldapConfigurationDao = Mock(LdapConfigurationDao)
def ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao)
configDao.getValue("ldap.bind.password") >> "password"
configDao.getValue("ldap.bind.principal") >> "cn=rmurphy,dc=cloudstack,dc=org"
when: "Get authentication is called"
String authentication = ldapConfiguration.getAuthentication()
then: "authentication should be set to simple"
authentication == "simple"
}
def "Test that getBaseDn returns dc=cloudstack,dc=org"() {
given: "We have a ConfigDao, LdapManager and ldapConfiguration with a baseDn value set."
def configDao = Mock(ConfigurationDao)
configDao.getValue("ldap.basedn") >> "dc=cloudstack,dc=org"
def ldapConfigurationDao = Mock(LdapConfigurationDao)
def ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao)
when: "Get basedn is called"
String baseDn = ldapConfiguration.getBaseDn();
then: "The set baseDn should be returned"
baseDn == "dc=cloudstack,dc=org"
}
def "Test that getEmailAttribute returns mail"() {
given: "Given that we have a ConfigDao, LdapManager and LdapConfiguration"
def configDao = Mock(ConfigurationDao)
@ -178,87 +149,12 @@ class LdapConfigurationSpec extends spock.lang.Specification {
LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao)
when: "A request is made to get the providerUrl"
String providerUrl = ldapConfiguration.getProviderUrl()
String providerUrl = ldapConfiguration.getProviderUrl(_)
then: "The providerUrl should be given."
providerUrl == "ldap://localhost:389"
}
def "Test that get search group principle returns successfully"() {
given: "We have a ConfigDao with a value for ldap.search.group.principle and an LdapConfiguration"
def configDao = Mock(ConfigurationDao)
configDao.getValue("ldap.search.group.principle") >> "cn=cloudstack,cn=users,dc=cloudstack,dc=org"
def ldapConfigurationDao = Mock(LdapConfigurationDao)
LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao)
when: "A request is made to get the search group principle"
String result = ldapConfiguration.getSearchGroupPrinciple();
then: "The result holds the same value configDao did"
result == "cn=cloudstack,cn=users,dc=cloudstack,dc=org"
}
def "Test that getTrustStorePassword resopnds"() {
given: "We have a ConfigDao with a value for truststore password"
def configDao = Mock(ConfigurationDao)
configDao.getValue("ldap.truststore.password") >> "password"
def ldapConfigurationDao = Mock(LdapConfigurationDao)
LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao)
when: "A request is made to get the truststore password"
String result = ldapConfiguration.getTrustStorePassword()
then: "The result is password"
result == "password";
}
def "Test that getSSLStatus can be true"() {
given: "We have a ConfigDao with values for truststore and truststore password set"
def configDao = Mock(ConfigurationDao)
configDao.getValue("ldap.truststore") >> "/tmp/ldap.ts"
configDao.getValue("ldap.truststore.password") >> "password"
def ldapConfigurationDao = Mock(LdapConfigurationDao)
LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao)
when: "A request is made to get the status of SSL"
boolean result = ldapConfiguration.getSSLStatus();
then: "The response should be true"
result == true
}
def "Test getgroupobject"() {
given: "We have configdao for ldap group object"
def configDao = Mock(ConfigurationDao)
configDao.getValue("ldap.group.object") >> groupObject
def ldapConfigurationDao = Mock(LdapConfigurationDao)
LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao)
def expectedResult = groupObject == null ? "groupOfUniqueNames" : groupObject
def result = ldapConfiguration.getGroupObject()
expect:
result == expectedResult
where:
groupObject << [null, "", "groupOfUniqueNames"]
}
def "Test getGroupUniqueMemeberAttribute"() {
given: "We have configdao for ldap group object"
def configDao = Mock(ConfigurationDao)
configDao.getValue("ldap.group.user.uniquemember") >> groupObject
def ldapConfigurationDao = Mock(LdapConfigurationDao)
LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapConfigurationDao)
def expectedResult = groupObject == null ? "uniquemember" : groupObject
def result = ldapConfiguration.getGroupUniqueMemeberAttribute()
expect:
result == expectedResult
where:
groupObject << [null, "", "uniquemember"]
}
def "Test getReadTimeout"() {
given: "We have configdao for ldap group object"
def configDao = Mock(ConfigurationDao)
@ -275,7 +171,7 @@ class LdapConfigurationSpec extends spock.lang.Specification {
def expected = timeout == null ? 1000 : timeout.toLong() //1000 is the default value
def result = ldapConfiguration.getReadTimeout()
def result = ldapConfiguration.getReadTimeout(null)
expect:
result == expected
where:
@ -298,7 +194,7 @@ class LdapConfigurationSpec extends spock.lang.Specification {
def expected = provider.equalsIgnoreCase("microsoftad") ? LdapUserManager.Provider.MICROSOFTAD : LdapUserManager.Provider.OPENLDAP //"openldap" is the default value
def result = ldapConfiguration.getLdapProvider()
def result = ldapConfiguration.getLdapProvider(null)
expect:
println "asserting for provider configuration: " + provider
result == expected

View File

@ -22,7 +22,6 @@ import spock.lang.Shared
import javax.naming.NamingException
import javax.naming.directory.SearchControls
import javax.naming.ldap.LdapContext
class LdapContextFactorySpec extends spock.lang.Specification {
@Shared
@ -41,7 +40,7 @@ class LdapContextFactorySpec extends spock.lang.Specification {
ldapConfiguration = Mock(LdapConfiguration)
ldapConfiguration.getFactory() >> "com.sun.jndi.ldap.LdapCtxFactory"
ldapConfiguration.getProviderUrl() >> "ldap://localhost:389"
ldapConfiguration.getProviderUrl(_) >> "ldap://localhost:389"
ldapConfiguration.getAuthentication() >> "none"
ldapConfiguration.getScope() >> SearchControls.SUBTREE_SCOPE
ldapConfiguration.getReturnAttributes() >> ["uid", "mail", "cn"]
@ -49,11 +48,11 @@ class LdapContextFactorySpec extends spock.lang.Specification {
ldapConfiguration.getEmailAttribute() >> "mail"
ldapConfiguration.getFirstnameAttribute() >> "givenname"
ldapConfiguration.getLastnameAttribute() >> "sn"
ldapConfiguration.getBaseDn() >> "dc=cloudstack,dc=org"
ldapConfiguration.getBaseDn(_) >> "dc=cloudstack,dc=org"
ldapConfiguration.getSSLStatus() >> true
ldapConfiguration.getTrustStore() >> "/tmp/ldap.ts"
ldapConfiguration.getTrustStorePassword() >> "password"
ldapConfiguration.getReadTimeout() >> 1000
ldapConfiguration.getReadTimeout(_) >> 1000
ldapConfiguration.getLdapPageSize() >> 1
username = "rmurphy"
@ -87,7 +86,7 @@ class LdapContextFactorySpec extends spock.lang.Specification {
def result = ldapContextFactory.getEnvironment(null, null, null, true)
then: "The resulting values should be set"
result['java.naming.provider.url'] == ldapConfiguration.getProviderUrl()
result['java.naming.provider.url'] == ldapConfiguration.getProviderUrl(null)
result['java.naming.factory.initial'] == ldapConfiguration.getFactory()
result['java.naming.security.principal'] == null
result['java.naming.security.authentication'] == ldapConfiguration.getAuthentication()
@ -102,7 +101,7 @@ class LdapContextFactorySpec extends spock.lang.Specification {
def result = ldapContextFactory.getEnvironment(principal, password, null, false)
then: "The resulting values should be set"
result['java.naming.provider.url'] == ldapConfiguration.getProviderUrl()
result['java.naming.provider.url'] == ldapConfiguration.getProviderUrl(null)
result['java.naming.factory.initial'] == ldapConfiguration.getFactory()
result['java.naming.security.principal'] == principal
result['java.naming.security.authentication'] == "simple"

View File

@ -16,54 +16,13 @@
// under the License.
package groovy.org.apache.cloudstack.ldap
import com.cloud.exception.InvalidParameterValueException
import org.apache.cloudstack.api.ServerApiException
import org.apache.cloudstack.api.command.LdapAddConfigurationCmd
import org.apache.cloudstack.api.response.LdapConfigurationResponse
import org.apache.cloudstack.ldap.LdapUser;
import org.apache.cloudstack.ldap.LdapManager;
import org.apache.cloudstack.api.command.LdapCreateAccountCmd;
import org.apache.cloudstack.context.CallContext;
import com.cloud.user.AccountService;
import com.cloud.user.UserAccount;
import com.cloud.user.UserAccountVO
import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException;
import javax.naming.NamingException
import org.apache.cloudstack.api.command.LdapCreateAccountCmd
import com.cloud.user.AccountService
class LdapCreateAccountCmdSpec extends spock.lang.Specification {
def "Test failure to retrive LDAP user"() {
given: "We have an LdapManager, AccountService and LdapCreateAccountCmd and LDAP user that doesn't exist"
LdapManager ldapManager = Mock(LdapManager)
ldapManager.getUser(_) >> { throw new NoLdapUserMatchingQueryException() }
AccountService accountService = Mock(AccountService)
def ldapCreateAccountCmd = Spy(LdapCreateAccountCmd, constructorArgs: [ldapManager, accountService])
ldapCreateAccountCmd.getCurrentContext() >> Mock(CallContext)
CallContext context = ldapCreateAccountCmd.getCurrentContext()
when: "An an account is created"
ldapCreateAccountCmd.execute()
then: "It fails and an exception is thrown"
thrown ServerApiException
}
def "Test failed creation due to a null response from cloudstack account creater"() {
given: "We have an LdapManager, AccountService and LdapCreateAccountCmd"
LdapManager ldapManager = Mock(LdapManager)
ldapManager.getUser(_) >> new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false)
AccountService accountService = Mock(AccountService)
def ldapCreateAccountCmd = Spy(LdapCreateAccountCmd, constructorArgs: [ldapManager, accountService])
ldapCreateAccountCmd.getCurrentContext() >> Mock(CallContext)
ldapCreateAccountCmd.createCloudstackUserAccount(_, _, _) >> null
when: "Cloudstack fail to create the user"
ldapCreateAccountCmd.execute()
then: "An exception is thrown"
thrown ServerApiException
}
def "Test command name"() {
given: "We have an LdapManager, AccountService and LdapCreateAccountCmd"
LdapManager ldapManager = Mock(LdapManager)
@ -105,7 +64,7 @@ class LdapCreateAccountCmdSpec extends spock.lang.Specification {
AccountService accountService = Mock(AccountService)
def ldapCreateAccountCmd = new LdapCreateAccountCmd(ldapManager, accountService);
when: "a user with an username, email, firstname and lastname is validated"
def result = ldapCreateAccountCmd.validateUser(new LdapUser("username", "email", "firstname", "lastname", "principal", "domain", false))
def result = ldapCreateAccountCmd.validateUser(new LdapUser("username", "email", "firstname", "lastname", "principal", "domain", false, null))
then: "the result is true"
result == true
}
@ -116,7 +75,7 @@ class LdapCreateAccountCmdSpec extends spock.lang.Specification {
AccountService accountService = Mock(AccountService)
def ldapCreateAccountCmd = new LdapCreateAccountCmd(ldapManager, accountService)
when: "A user with no email address attempts to validate"
ldapCreateAccountCmd.validateUser(new LdapUser("username", null, "firstname", "lastname", "principal", "domain", false))
ldapCreateAccountCmd.validateUser(new LdapUser("username", null, "firstname", "lastname", "principal", "domain", false, null))
then: "An exception is thrown"
thrown Exception
}
@ -138,7 +97,7 @@ class LdapCreateAccountCmdSpec extends spock.lang.Specification {
AccountService accountService = Mock(AccountService)
def ldapCreateAccountCmd = new LdapCreateAccountCmd(ldapManager, accountService)
when: "A user with no lastname attempts to validate"
ldapCreateAccountCmd.validateUser(new LdapUser("username", "email", "firstname", null, "principal", "domain", false))
ldapCreateAccountCmd.validateUser(new LdapUser("username", "email", "firstname", null, "principal", "domain", false, null))
then: "An exception is thown"
thrown Exception
}

View File

@ -27,7 +27,7 @@ class LdapDeleteConfigurationCmdSpec extends spock.lang.Specification {
def "Test failed response from execute"() {
given: "We have an LdapManager and LdapDeleteConfigurationCmd"
def ldapManager = Mock(LdapManager)
ldapManager.deleteConfiguration(_) >> { throw new InvalidParameterValueException() }
ldapManager.deleteConfiguration(_, 0, null) >> { throw new InvalidParameterValueException() }
def ldapDeleteConfigurationCmd = new LdapDeleteConfigurationCmd(ldapManager)
when:"LdapDeleteConfigurationCmd is executed and no configuration exists"
ldapDeleteConfigurationCmd.execute()
@ -48,7 +48,7 @@ class LdapDeleteConfigurationCmdSpec extends spock.lang.Specification {
def "Test successful response from execute"() {
given: "We have an LdapManager and LdapDeleteConfigurationCmd"
def ldapManager = Mock(LdapManager)
ldapManager.deleteConfiguration(_) >> new LdapConfigurationResponse("localhost")
ldapManager.deleteConfiguration(_, 0, null) >> new LdapConfigurationResponse("localhost")
def ldapDeleteConfigurationCmd = new LdapDeleteConfigurationCmd(ldapManager)
when: "LdapDeleteConfigurationCmd is executed"
ldapDeleteConfigurationCmd.execute()

View File

@ -24,10 +24,8 @@ import com.cloud.user.DomainService
import com.cloud.user.User
import com.cloud.user.UserAccountVO
import com.cloud.user.UserVO
import org.apache.cloudstack.api.command.LdapCreateAccountCmd
import org.apache.cloudstack.api.command.LdapImportUsersCmd
import org.apache.cloudstack.api.response.LdapUserResponse
import org.apache.cloudstack.context.CallContext
import org.apache.cloudstack.ldap.LdapManager
import org.apache.cloudstack.ldap.LdapUser
@ -53,9 +51,9 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification {
def accountService = Mock(AccountService)
List<LdapUser> users = new ArrayList()
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
ldapManager.getUsers() >> users
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
ldapManager.getUsers(null) >> users
LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")
ldapManager.createLdapUserResponse(_) >>> [response1, response2]
@ -81,9 +79,9 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification {
def accountService = Mock(AccountService)
List<LdapUser> users = new ArrayList()
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
ldapManager.getUsersInGroup("TestGroup") >> users
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
ldapManager.getUsersInGroup("TestGroup", null) >> users
LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")
ldapManager.createLdapUserResponse(_) >>> [response1, response2]
@ -110,9 +108,9 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification {
def accountService = Mock(AccountService)
List<LdapUser> users = new ArrayList()
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
ldapManager.getUsersInGroup("TestGroup") >> users
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
ldapManager.getUsersInGroup("TestGroup", null) >> users
LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")
ldapManager.createLdapUserResponse(_) >>> [response1, response2]
@ -139,9 +137,9 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification {
def accountService = Mock(AccountService)
List<LdapUser> users = new ArrayList()
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
ldapManager.getUsers() >> users
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
ldapManager.getUsers(null) >> users
LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")
ldapManager.createLdapUserResponse(_) >>> [response1, response2]
@ -169,8 +167,8 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification {
ldapImportUsersCmd.domainId = varDomainId
ldapImportUsersCmd.groupName = varGroupName
def ldapUser1 = new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false)
def ldapUser2 = new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false);
def ldapUser1 = new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null)
def ldapUser2 = new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null);
Domain domain = new DomainVO(expectedDomainName, 1L, 1L, expectedDomainName, UUID.randomUUID().toString());
if (varDomainId != null) {
@ -204,8 +202,8 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification {
given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd"
def ldapManager = Mock(LdapManager)
List<LdapUser> users = new ArrayList()
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
ldapManager.getUsers() >> users
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
ldapManager.getUsers(null) >> users
LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
ldapManager.createLdapUserResponse(_) >>> response1
@ -234,8 +232,8 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification {
given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd"
def ldapManager = Mock(LdapManager)
List<LdapUser> users = new ArrayList()
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
ldapManager.getUsers() >> users
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
ldapManager.getUsers(null) >> users
LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
ldapManager.createLdapUserResponse(_) >>> response1
@ -263,8 +261,8 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification {
given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd"
def ldapManager = Mock(LdapManager)
List<LdapUser> users = new ArrayList()
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
ldapManager.getUsers() >> users
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
ldapManager.getUsers(null) >> users
LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")
ldapManager.createLdapUserResponse(_) >>> response1

View File

@ -40,7 +40,7 @@ class LdapListUsersCmdSpec extends spock.lang.Specification {
def "Test successful empty response from execute"() {
given: "We have a LdapManager with no users, QueryService and a LdapListUsersCmd"
def ldapManager = Mock(LdapManager)
ldapManager.getUsers() >> {throw new NoLdapUserMatchingQueryException()}
ldapManager.getUsers(null) >> {throw new NoLdapUserMatchingQueryException()}
def queryService = Mock(QueryService)
def ldapListUsersCmd = new LdapListUsersCmd(ldapManager, queryService)
when: "LdapListUsersCmd is executed"
@ -53,8 +53,8 @@ class LdapListUsersCmdSpec extends spock.lang.Specification {
given: "We have an LdapManager, one user, QueryService and a LdapListUsersCmd"
def ldapManager = Mock(LdapManager)
List<LdapUser> users = new ArrayList()
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false))
ldapManager.getUsers() >> users
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false, null))
ldapManager.getUsers(null) >> users
LdapUserResponse response = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null)
ldapManager.createLdapUserResponse(_) >> response
def queryService = Mock(QueryService)
@ -92,7 +92,7 @@ class LdapListUsersCmdSpec extends spock.lang.Specification {
queryService.searchForUsers(_) >> queryServiceResponse
def ldapUser = new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false)
def ldapUser = new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false, null)
def ldapListUsersCmd = new LdapListUsersCmd(ldapManager,queryService)
when: "isACloudstackUser is executed"
@ -109,7 +109,7 @@ class LdapListUsersCmdSpec extends spock.lang.Specification {
queryService.searchForUsers(_) >> new ListResponse<UserResponse>()
def ldapUser = new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false)
def ldapUser = new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false, null)
def ldapListUsersCmd = new LdapListUsersCmd(ldapManager,queryService)
when: "isACloudstackUser is executed"

View File

@ -52,7 +52,7 @@ class LdapManagerImplSpec extends spock.lang.Specification {
ldapContextFactory.createBindContext() >> { throw new NoLdapUserMatchingQueryException() }
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration)
when: "We search for a user but there is a bind issue"
ldapManager.getUser("rmurphy")
ldapManager.getUser("rmurphy", null)
then: "an exception is thrown"
thrown NoLdapUserMatchingQueryException
}
@ -68,7 +68,7 @@ class LdapManagerImplSpec extends spock.lang.Specification {
ldapContextFactory.createBindContext() >> { throw new NamingException() }
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration)
when: "We search for a group of users but there is a bind issue"
ldapManager.getUsers()
ldapManager.getUsers(null)
then: "An exception is thrown"
thrown NoLdapUserMatchingQueryException
}
@ -116,7 +116,7 @@ class LdapManagerImplSpec extends spock.lang.Specification {
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration)
when: "A ldap user response is generated"
def result = ldapManager.createLdapUserResponse(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org",
"engineering", false))
"engineering", false, null))
then: "The result of the response should match the given ldap user"
result.username == "rmurphy"
result.email == "rmurphy@test.com"
@ -136,11 +136,11 @@ class LdapManagerImplSpec extends spock.lang.Specification {
ldapUserManagerFactory.getInstance(_) >> ldapUserManager
ldapContextFactory.createBindContext() >> null
List<LdapUser> users = new ArrayList<>();
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false))
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false, null))
ldapUserManager.getUsers(_) >> users;
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration)
when: "We search for a group of users"
def result = ldapManager.getUsers()
def result = ldapManager.getUsers(null)
then: "A list greater than 0 is returned"
result.size() > 0;
}
@ -154,10 +154,10 @@ class LdapManagerImplSpec extends spock.lang.Specification {
def ldapConfiguration = Mock(LdapConfiguration)
ldapUserManagerFactory.getInstance(_) >> ldapUserManager
ldapContextFactory.createBindContext() >> null
ldapUserManager.getUser(_, _) >> new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false)
ldapUserManager.getUser(_, _, _) >> new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false, null)
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration)
when: "We search for a user"
def result = ldapManager.getUser("rmurphy")
def result = ldapManager.getUser("rmurphy", null)
then: "The user is returned"
result.username == "rmurphy"
result.email == "rmurphy@test.com"
@ -192,9 +192,9 @@ class LdapManagerImplSpec extends spock.lang.Specification {
ldapUserManagerFactory.getInstance(_) >> ldapUserManager
def ldapConfiguration = Mock(LdapConfiguration)
def ldapManager = Spy(LdapManagerImpl, constructorArgs: [ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration])
ldapManager.getUser(_) >> { new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null) }
ldapManager.getUser(_, null) >> { new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null) }
when: "The user attempts to authenticate with a bad password"
def result = ldapManager.canAuthenticate("rmurphy", "password")
def result = ldapManager.canAuthenticate("rmurphy", "password", null)
then: "The authentication fails"
result == false
}
@ -210,7 +210,7 @@ class LdapManagerImplSpec extends spock.lang.Specification {
ldapConfigurationDao.findByHostname(_) >> null
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration)
when: "A ldap configuration that doesn't exist is deleted"
ldapManager.deleteConfiguration("localhost")
ldapManager.deleteConfiguration("localhost", 0, null)
then: "A exception is thrown"
thrown InvalidParameterValueException
}
@ -242,9 +242,9 @@ class LdapManagerImplSpec extends spock.lang.Specification {
def ldapConfiguration = Mock(LdapConfiguration)
ldapUserManagerFactory.getInstance(_) >> ldapUserManager
def ldapManager = Spy(LdapManagerImpl, constructorArgs: [ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration])
ldapManager.getUser(_) >> { new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null) }
ldapManager.getUser(_, null) >> { new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null) }
when: "A user authenticates"
def result = ldapManager.canAuthenticate("rmurphy", "password")
def result = ldapManager.canAuthenticate("rmurphy", "password", null)
then: "The result is true"
result == true
}
@ -265,7 +265,7 @@ class LdapManagerImplSpec extends spock.lang.Specification {
ldapConfigurationDao.remove(_) >> null
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration)
when: "A ldap configuration is deleted"
def result = ldapManager.deleteConfiguration("localhost")
def result = ldapManager.deleteConfiguration("localhost", 0, null)
then: "The deleted configuration is returned"
result.hostname == "localhost"
result.port == 389
@ -282,7 +282,7 @@ class LdapManagerImplSpec extends spock.lang.Specification {
ldapContextFactory.createBindContext() >> null;
List<LdapUser> users = new ArrayList<LdapUser>();
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false))
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null))
ldapUserManager.getUsers(_, _) >> users;
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration)
@ -424,11 +424,11 @@ class LdapManagerImplSpec extends spock.lang.Specification {
ldapUserManagerFactory.getInstance(_) >> ldapUserManager
ldapContextFactory.createBindContext() >> null
List<LdapUser> users = new ArrayList<>();
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", "engineering", false))
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", "engineering", false, null))
ldapUserManager.getUsersInGroup("engineering", _) >> users;
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration)
when: "We search for a group of users"
def result = ldapManager.getUsersInGroup("engineering")
def result = ldapManager.getUsersInGroup("engineering", null)
then: "A list greater of size one is returned"
result.size() == 1;
}
@ -524,7 +524,7 @@ class LdapManagerImplSpec extends spock.lang.Specification {
def type = "GROUP"
def name = "CN=test,DC=citrix,DC=com"
ldapUserManager.getUser(username, type, name, _) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", true)
ldapUserManager.getUser(username, type, name, _) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", true, null)
when:
LdapUser user = ldapManager.getUser(username, type, name)
@ -574,7 +574,7 @@ class LdapManagerImplSpec extends spock.lang.Specification {
def type = "GROUP"
def name = "CN=test,DC=citrix,DC=com"
ldapUserManager.getUser(username, type, name, _) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false)
ldapUserManager.getUser(username, type, name, _) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false, null)
when:
LdapUser user = ldapManager.getUser(username, type, name)

View File

@ -48,7 +48,7 @@ class LdapSearchUserCmdSpec extends spock.lang.Specification {
given: "We have an Ldap manager and ldap user search cmd"
def ldapManager = Mock(LdapManager)
List<LdapUser> users = new ArrayList()
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false))
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false, null))
ldapManager.searchUsers(_) >> users
LdapUserResponse response = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null)
ldapManager.createLdapUserResponse(_) >> response

View File

@ -22,7 +22,7 @@ class LdapUserSpec extends spock.lang.Specification {
def "Testing LdapUsers hashCode generation"() {
given:
def userA = new LdapUser(usernameA, "", "", "", "", "", false)
def userA = new LdapUser(usernameA, "", "", "", "", "", false, null)
expect:
userA.hashCode() == usernameA.hashCode()
where:
@ -31,8 +31,8 @@ class LdapUserSpec extends spock.lang.Specification {
def "Testing that LdapUser successfully gives the correct result for a compare to"() {
given: "You have created two LDAP user objects"
def userA = new LdapUser(usernameA, "", "", "", "", "", false)
def userB = new LdapUser(usernameB, "", "", "", "", "", false)
def userA = new LdapUser(usernameA, "", "", "", "", "", false, null)
def userB = new LdapUser(usernameB, "", "", "", "", "", false, null)
expect: "That when compared the result is less than or equal to 0"
userA.compareTo(userB) <= 0
where: "The following values are used"
@ -43,8 +43,8 @@ class LdapUserSpec extends spock.lang.Specification {
def "Testing that LdapUsers equality"() {
given:
def userA = new LdapUser(usernameA, "", "", "", "", "", false)
def userB = new LdapUser(usernameB, "", "", "", "", "", false)
def userA = new LdapUser(usernameA, "", "", "", "", "", false, null)
def userB = new LdapUser(usernameB, "", "", "", "", "", false, null)
expect:
userA.equals(userA) == true
userA.equals(new Object()) == false
@ -56,7 +56,7 @@ class LdapUserSpec extends spock.lang.Specification {
def "Testing that the username is correctly set with the ldap object"() {
given: "You have created a LDAP user object with a username"
def user = new LdapUser(username, "", "", "", "", "", false)
def user = new LdapUser(username, "", "", "", "", "", false, null)
expect: "The username is equal to the given data source"
user.getUsername() == username
where: "The username is set to "
@ -65,7 +65,7 @@ class LdapUserSpec extends spock.lang.Specification {
def "Testing the email is correctly set with the ldap object"() {
given: "You have created a LDAP user object with a email"
def user = new LdapUser("", email, "", "", "", "", false)
def user = new LdapUser("", email, "", "", "", "", false, null)
expect: "The email is equal to the given data source"
user.getEmail() == email
where: "The email is set to "
@ -74,7 +74,7 @@ class LdapUserSpec extends spock.lang.Specification {
def "Testing the firstname is correctly set with the ldap object"() {
given: "You have created a LDAP user object with a firstname"
def user = new LdapUser("", "", firstname, "", "", "", false)
def user = new LdapUser("", "", firstname, "", "", "", false, null)
expect: "The firstname is equal to the given data source"
user.getFirstname() == firstname
where: "The firstname is set to "
@ -83,7 +83,7 @@ class LdapUserSpec extends spock.lang.Specification {
def "Testing the lastname is correctly set with the ldap object"() {
given: "You have created a LDAP user object with a lastname"
def user = new LdapUser("", "", "", lastname, "", "", false)
def user = new LdapUser("", "", "", lastname, "", "", false, null)
expect: "The lastname is equal to the given data source"
user.getLastname() == lastname
where: "The lastname is set to "
@ -92,7 +92,7 @@ class LdapUserSpec extends spock.lang.Specification {
def "Testing the principal is correctly set with the ldap object"() {
given: "You have created a LDAP user object with a principal"
def user = new LdapUser("", "", "", "", principal, "", false)
def user = new LdapUser("", "", "", "", principal, "", false, null)
expect: "The principal is equal to the given data source"
user.getPrincipal() == principal
where: "The principal is set to "
@ -101,7 +101,7 @@ class LdapUserSpec extends spock.lang.Specification {
def "Testing the domain is correctly set with the ldap object"() {
given: "You have created a LDAP user object with a principal"
def user = new LdapUser("", "", "", "", "", domain, false)
def user = new LdapUser("", "", "", "", "", domain, false, null)
expect: "The principal is equal to the given data source"
user.getDomain() == domain
where: "The username is set to "

View File

@ -79,7 +79,7 @@ class LinkDomainToLdapCmdSpec extends Specification {
LinkDomainToLdapResponse response = new LinkDomainToLdapResponse(domainId, type, name, (short)accountType)
_ldapManager.linkDomainToLdap(_,_,_,_) >> response
_ldapManager.getUser(username, type, name) >> new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", name, "ccp", true)
_ldapManager.getUser(username, type, name) >> new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", name, "ccp", true, null)
linkDomainToLdapCmd.admin = username
linkDomainToLdapCmd.type = type
@ -107,7 +107,7 @@ class LinkDomainToLdapCmdSpec extends Specification {
LinkDomainToLdapResponse response = new LinkDomainToLdapResponse(domainId.toString(), type, name, (short)accountType)
_ldapManager.linkDomainToLdap(_,_,_,_) >> response
_ldapManager.getUser(username, type, name) >> new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", name, "ccp", false)
_ldapManager.getUser(username, type, name) >> new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", name, "ccp", false, null)
_accountService.getActiveAccountByName(username, domainId) >> Mock(Account)
@ -204,7 +204,7 @@ class LinkDomainToLdapCmdSpec extends Specification {
LinkDomainToLdapResponse response = new LinkDomainToLdapResponse(domainId.toString(), type, name, (short)accountType)
_ldapManager.linkDomainToLdap(_,_,_,_) >> response
_ldapManager.getUser(username, type, name) >> new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", name, "ccp", false)
_ldapManager.getUser(username, type, name) >> new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", name, "ccp", false, null)
_accountService.getActiveAccountByName(username, domainId) >> null
UserAccount userAccount = Mock(UserAccount)

View File

@ -17,14 +17,12 @@
package groovy.org.apache.cloudstack.ldap
import org.apache.cloudstack.ldap.LdapConfiguration
import org.apache.cloudstack.ldap.LdapUserManager
import org.apache.cloudstack.ldap.OpenLdapUserManagerImpl
import spock.lang.Shared
import javax.naming.NamingException
import javax.naming.directory.Attribute
import javax.naming.directory.Attributes
import javax.naming.directory.InitialDirContext
import javax.naming.directory.SearchControls
import javax.naming.directory.SearchResult
import javax.naming.ldap.InitialLdapContext
@ -167,12 +165,12 @@ class OpenLdapUserManagerSpec extends spock.lang.Specification {
ldapConfiguration.getEmailAttribute() >> "mail"
ldapConfiguration.getFirstnameAttribute() >> "givenname"
ldapConfiguration.getLastnameAttribute() >> "sn"
ldapConfiguration.getBaseDn() >> "dc=cloudstack,dc=org"
ldapConfiguration.getBaseDn(_) >> "dc=cloudstack,dc=org"
ldapConfiguration.getCommonNameAttribute() >> "cn"
ldapConfiguration.getGroupObject() >> "groupOfUniqueNames"
ldapConfiguration.getGroupUniqueMemeberAttribute() >> "uniquemember"
ldapConfiguration.getGroupUniqueMemberAttribute(_) >> "uniquemember"
ldapConfiguration.getLdapPageSize() >> 1
ldapConfiguration.getReadTimeout() >> 1000
ldapConfiguration.getReadTimeout(_) >> 1000
username = "rmurphy"
email = "rmurphy@test.com"
@ -186,7 +184,7 @@ class OpenLdapUserManagerSpec extends spock.lang.Specification {
def attributes = createUserAttributes(username, email, firstname, lastname)
def search = createSearchResult(attributes)
def userManager = new OpenLdapUserManagerImpl(ldapConfiguration)
def result = userManager.createUser(search)
def result = userManager.createUser(search,)
expect: "The crated user the data supplied from LDAP"
@ -290,7 +288,7 @@ class OpenLdapUserManagerSpec extends spock.lang.Specification {
def ldapUserManager = new OpenLdapUserManagerImpl(ldapConfiguration)
when: "A request for users is made"
def result = ldapUserManager.getUsersInGroup("engineering", createGroupSearchContextOneUser())
def result = ldapUserManager.getUsersInGroup("engineering", createGroupSearchContextOneUser(),)
then: "one user is returned"
result.size() == 1
}
@ -300,7 +298,7 @@ class OpenLdapUserManagerSpec extends spock.lang.Specification {
def ldapUserManager = new OpenLdapUserManagerImpl(ldapConfiguration)
when: "A request for users is made"
def result = ldapUserManager.getUsersInGroup("engineering", createGroupSearchContextNoUser())
def result = ldapUserManager.getUsersInGroup("engineering", createGroupSearchContextNoUser(),)
then: "no user is returned"
result.size() == 0
}

View File

@ -0,0 +1,56 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.command;
import java.lang.reflect.Field;
interface LdapConfigurationChanger {
/**
* sets a possibly not accessible field of the target object.
* @param target the object to set a hidden fields value in.
* @param name the name of the field to set.
* @param o intended value for the field "name"
* @throws IllegalAccessException
* @throws NoSuchFieldException
*/
default void setHiddenField(Object target, final String name, final Object o) throws IllegalAccessException, NoSuchFieldException {
Class<?> klas = target.getClass();
Field f = getFirstFoundField(name, klas);
f.setAccessible(true);
f.set(target, o);
}
/**
* the first field found by this name in the class "klas" or any of it's superclasses except for {@code Object}. Implementers of this interface can decide to also return any field in implemented interfaces or in {@code Object}.
*
* @param name of the field to find
* @param klas class to gat a field by name "name" from
* @return a {@code Field} by the name "name"
* @throws NoSuchFieldException
*/
default Field getFirstFoundField(String name, Class<?> klas) throws NoSuchFieldException {
try {
return klas.getDeclaredField(name);
} catch (NoSuchFieldException e) {
Class<?> parent = klas.getSuperclass();
if(parent.equals(Object.class)) {
throw e;
}
return getFirstFoundField(name, parent);
}
}
}

View File

@ -0,0 +1,72 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.command;
import com.cloud.user.Account;
import com.cloud.user.AccountService;
import org.apache.cloudstack.acl.RoleService;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.ldap.LdapManager;
import org.apache.cloudstack.ldap.LdapUser;
import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.isNull;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(MockitoJUnitRunner.class)
public class LdapCreateAccountCmdTest implements LdapConfigurationChanger {
@Mock
LdapManager ldapManager;
@Mock
AccountService accountService;
@Mock
RoleService roleService;
LdapCreateAccountCmd ldapCreateAccountCmd;
@Before
public void setUp() throws NoSuchFieldException, IllegalAccessException {
ldapCreateAccountCmd = spy(new LdapCreateAccountCmd(ldapManager, accountService));
ldapCreateAccountCmd.roleService = roleService;
setHiddenField(ldapCreateAccountCmd,"accountType", Account.ACCOUNT_TYPE_DOMAIN_ADMIN);
}
@Test(expected = ServerApiException.class)
public void failureToRetrieveLdapUser() throws Exception {
// We have an LdapManager, AccountService and LdapCreateAccountCmd and LDAP user that doesn't exist
when(ldapManager.getUser(anyString(), isNull(Long.class))).thenThrow(NoLdapUserMatchingQueryException.class);
ldapCreateAccountCmd.execute();
fail("An exception should have been thrown: " + ServerApiException.class);
}
@Test(expected = ServerApiException.class)
public void failedCreationDueToANullResponseFromCloudstackAccountCreater() throws Exception {
// We have an LdapManager, AccountService and LdapCreateAccountCmd
LdapUser mrMurphy = new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null);
when(ldapManager.getUser(anyString(), isNull(Long.class))).thenReturn(mrMurphy);
ldapCreateAccountCmd.execute();
fail("An exception should have been thrown: " + ServerApiException.class);
}
}

View File

@ -0,0 +1,85 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.command;
import com.cloud.domain.Domain;
import com.cloud.domain.DomainVO;
import com.cloud.user.Account;
import com.cloud.user.AccountService;
import com.cloud.user.DomainService;
import org.apache.cloudstack.acl.RoleService;
import org.apache.cloudstack.api.response.ListResponse;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.apache.cloudstack.api.response.LdapUserResponse;
import org.apache.cloudstack.ldap.LdapManager;
import org.apache.cloudstack.ldap.LdapUser;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import static junit.framework.TestCase.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(MockitoJUnitRunner.class)
public class LdapImportUsersCmdTest implements LdapConfigurationChanger {
@Mock
LdapManager ldapManager;
@Mock
AccountService accountService;
@Mock
DomainService domainService;
@Mock
RoleService roleService;
LdapImportUsersCmd ldapImportUsersCmd;
@Before
public void setUp() throws NoSuchFieldException, IllegalAccessException {
ldapImportUsersCmd = spy(new LdapImportUsersCmd(ldapManager, domainService, accountService));
ldapImportUsersCmd.roleService = roleService;
setHiddenField(ldapImportUsersCmd, "accountType", Account.ACCOUNT_TYPE_DOMAIN_ADMIN);
}
@Test
public void successfulResponseFromExecute() throws Exception {
List<LdapUser> users = new ArrayList();
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null));
users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false, null));
when(ldapManager.getUsers(null)).thenReturn(users);
LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering");
LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering");
when(ldapManager.createLdapUserResponse(any(LdapUser.class))).thenReturn(response1).thenReturn(response2);
Domain domain = new DomainVO("engineering", 1L, 1L, "engineering", UUID.randomUUID().toString());
when(domainService.getDomainByName("engineering", 1L)).thenReturn(null, domain);
when(domainService.createDomain(eq("engineering"), eq(1L), eq("engineering"), anyString())).thenReturn(domain);
ldapImportUsersCmd.execute();
ListResponse<LdapUserResponse> resp = (ListResponse<LdapUserResponse>)ldapImportUsersCmd.getResponseObject();
assertEquals(" when LdapListUsersCmd is executed, a list of size 2 should be returned", 2, resp.getResponses().size());
}
}

View File

@ -0,0 +1,97 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.command;
import com.cloud.user.Account;
import com.cloud.user.AccountService;
import com.cloud.user.User;
import com.cloud.user.UserAccountVO;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.response.LinkAccountToLdapResponse;
import org.apache.cloudstack.ldap.LdapManager;
import org.apache.cloudstack.ldap.LdapUser;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(MockitoJUnitRunner.class)
public class LinkAccountToLdapCmdTest implements LdapConfigurationChanger {
@Mock
LdapManager ldapManager;
@Mock
AccountService accountService;
LinkAccountToLdapCmd linkAccountToLdapCmd;
@Before
public void setUp() throws NoSuchFieldException, IllegalAccessException {
linkAccountToLdapCmd = new LinkAccountToLdapCmd();
setHiddenField(linkAccountToLdapCmd, "_ldapManager", ldapManager);
setHiddenField(linkAccountToLdapCmd, "_accountService", accountService);
}
@Test
public void execute() throws Exception {
// test with valid params and with admin who doesnt exist in cloudstack
long domainId = 1;
String type = "GROUP";
String ldapDomain = "CN=test,DC=ccp,DC=Citrix,DC=com";
short accountType = Account.ACCOUNT_TYPE_DOMAIN_ADMIN;
String username = "admin";
long accountId = 24;
String accountName = "test";
setHiddenField(linkAccountToLdapCmd, "ldapDomain", ldapDomain);
setHiddenField(linkAccountToLdapCmd, "admin", username);
setHiddenField(linkAccountToLdapCmd, "type", type);
setHiddenField(linkAccountToLdapCmd, "domainId", domainId);
setHiddenField(linkAccountToLdapCmd, "accountType", accountType);
setHiddenField(linkAccountToLdapCmd, "accountName", accountName);
LinkAccountToLdapResponse response = new LinkAccountToLdapResponse(String.valueOf(domainId), type, ldapDomain, (short)accountType, username, accountName);
when(ldapManager.linkAccountToLdap(linkAccountToLdapCmd)).thenReturn(response);
when(ldapManager.getUser(username, type, ldapDomain, 1L))
.thenReturn(new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", ldapDomain, "ccp", false, null));
when(accountService.getActiveAccountByName(username, domainId)).thenReturn(null);
UserAccountVO userAccount = new UserAccountVO();
userAccount.setAccountId(24);
when(accountService.createUserAccount(eq(username), eq(""), eq("Admin"), eq("Admin"), eq("admin@ccp.citrix.com"), isNull(String.class),
eq(username), eq(Account.ACCOUNT_TYPE_DOMAIN_ADMIN), eq(RoleType.DomainAdmin.getId()), eq(domainId), isNull(String.class),
(java.util.Map<String,String>)isNull(), anyString(), anyString(), eq(User.Source.LDAP))).thenReturn(userAccount);
linkAccountToLdapCmd.execute();
LinkAccountToLdapResponse result = (LinkAccountToLdapResponse)linkAccountToLdapCmd.getResponseObject();
assertEquals("objectName", linkAccountToLdapCmd.APINAME, result.getObjectName());
assertEquals("commandName", linkAccountToLdapCmd.getCommandName(), result.getResponseName());
assertEquals("domainId", String.valueOf(domainId), result.getDomainId());
assertEquals("type", type, result.getType());
assertEquals("name", ldapDomain, result.getLdapDomain());
assertEquals("accountId", String.valueOf(accountId), result.getAdminId());
}
}

View File

@ -0,0 +1,98 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.command;
import com.cloud.user.Account;
import com.cloud.user.AccountService;
import com.cloud.user.User;
import com.cloud.user.UserAccountVO;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.response.LinkDomainToLdapResponse;
import org.apache.cloudstack.ldap.LdapManager;
import org.apache.cloudstack.ldap.LdapUser;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(MockitoJUnitRunner.class)
public class LinkDomainToLdapCmdTest implements LdapConfigurationChanger
{
@Mock
LdapManager ldapManager;
@Mock
AccountService accountService;
LinkDomainToLdapCmd linkDomainToLdapCmd;
@Before
public void setUp() throws NoSuchFieldException, IllegalAccessException {
linkDomainToLdapCmd = new LinkDomainToLdapCmd();
setHiddenField(linkDomainToLdapCmd, "_ldapManager", ldapManager);
setHiddenField(linkDomainToLdapCmd, "_accountService", accountService);
}
@After
public void tearDown() {
}
@Test
public void execute() throws Exception {
// test with valid params and with admin who doesnt exist in cloudstack
Long domainId = 1L;
String type = "GROUP";
String ldapDomain = "CN=test,DC=ccp,DC=Citrix,DC=com";
short accountType = Account.ACCOUNT_TYPE_DOMAIN_ADMIN;
String username = "admin";
long accountId = 24;
setHiddenField(linkDomainToLdapCmd, "ldapDomain", ldapDomain);
setHiddenField(linkDomainToLdapCmd, "admin", username);
setHiddenField(linkDomainToLdapCmd, "type", type);
setHiddenField(linkDomainToLdapCmd, "domainId", domainId);
setHiddenField(linkDomainToLdapCmd, "accountType", accountType);
LinkDomainToLdapResponse response = new LinkDomainToLdapResponse(domainId.toString(), type, ldapDomain, (short)accountType);
when(ldapManager.linkDomainToLdap(linkDomainToLdapCmd)).thenReturn(response);
when(ldapManager.getUser(username, type, ldapDomain, 1L)).thenReturn(new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", ldapDomain, "ccp", false, null));
when(accountService.getActiveAccountByName(username, domainId)).thenReturn(null);
UserAccountVO userAccount = new UserAccountVO();
userAccount.setAccountId(24);
when(accountService.createUserAccount(eq(username), eq(""), eq("Admin"), eq("Admin"), eq("admin@ccp.citrix.com"), isNull(String.class),
eq(username), eq(Account.ACCOUNT_TYPE_DOMAIN_ADMIN), eq(RoleType.DomainAdmin.getId()), eq(domainId), isNull(String.class),
(java.util.Map<String,String>)isNull(), anyString(), anyString(), eq(User.Source.LDAP))).thenReturn(userAccount);
linkDomainToLdapCmd.execute();
LinkDomainToLdapResponse result = (LinkDomainToLdapResponse)linkDomainToLdapCmd.getResponseObject();
assertEquals("objectName", "LinkDomainToLdap", result.getObjectName());
assertEquals("commandName", linkDomainToLdapCmd.getCommandName(), result.getResponseName());
assertEquals("domainId", domainId.toString(), result.getDomainId());
assertEquals("type", type, result.getType());
assertEquals("name", ldapDomain, result.getLdapDomain());
assertEquals("accountId", String.valueOf(accountId), result.getAdminId());
}
}

View File

@ -0,0 +1,141 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.ldap;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.ldap.dao.LdapConfigurationDao;
import org.apache.cloudstack.ldap.dao.LdapConfigurationDaoImpl;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@RunWith(MockitoJUnitRunner.class)
public class LdapConfigurationTest {
LdapConfigurationDao ldapConfigurationDao;
LdapConfiguration ldapConfiguration;
private void overrideConfigValue(final String configKeyName, final Object o) throws IllegalAccessException, NoSuchFieldException {
Field configKey = LdapConfiguration.class.getDeclaredField(configKeyName);
configKey.setAccessible(true);
ConfigKey key = (ConfigKey)configKey.get(ldapConfiguration);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(configKey, configKey.getModifiers() & ~Modifier.FINAL);
Field f = ConfigKey.class.getDeclaredField("_value");
f.setAccessible(true);
modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);
f.set(key, o);
Field dynamic = ConfigKey.class.getDeclaredField("_isDynamic");
dynamic.setAccessible(true);
modifiersField.setInt(dynamic, dynamic.getModifiers() & ~Modifier.FINAL);
dynamic.setBoolean(key, false);
}
@Before
public void init() throws Exception {
ldapConfigurationDao = new LdapConfigurationDaoImpl();
ldapConfiguration = new LdapConfiguration(ldapConfigurationDao);;
}
@Test
public void getAuthenticationReturnsSimple() throws Exception {
overrideConfigValue("ldapBindPrincipal", "cn=bla");
overrideConfigValue("ldapBindPassword", "pw");
String authentication = ldapConfiguration.getAuthentication(null);
assertEquals("authentication should be set to simple", "simple", authentication);
}
@Test
public void getBaseDnReturnsABaseDn() throws Exception {
overrideConfigValue("ldapBaseDn", "dc=cloudstack,dc=org");
String baseDn = ldapConfiguration.getBaseDn(null);
assertEquals("The set baseDn should be returned","dc=cloudstack,dc=org", baseDn);
}
@Test
public void getGroupUniqueMemberAttribute() throws Exception {
String [] groupNames = {"bla", "uniquemember", "memberuid", "", null};
for (String groupObject: groupNames) {
overrideConfigValue("ldapGroupUniqueMemberAttribute", groupObject);
String expectedResult = null;
if(groupObject == null) {
expectedResult = "uniquemember";
} else {
expectedResult = groupObject;
};
String result = ldapConfiguration.getGroupUniqueMemberAttribute(null);
assertEquals("testing for " + groupObject, expectedResult, result);
}
}
@Test
public void getSSLStatusCanBeTrue() throws Exception {
// given: "We have a ConfigDao with values for truststore and truststore password set"
overrideConfigValue("ldapTrustStore", "/tmp/ldap.ts");
overrideConfigValue("ldapTrustStorePassword", "password");
assertTrue("A request is made to get the status of SSL should result in true", ldapConfiguration.getSSLStatus());
}
@Test
public void getSearchGroupPrincipleReturnsSuccessfully() throws Exception {
// We have a ConfigDao with a value for ldap.search.group.principle and an LdapConfiguration
overrideConfigValue("ldapSearchGroupPrinciple", "cn=cloudstack,cn=users,dc=cloudstack,dc=org");
String result = ldapConfiguration.getSearchGroupPrinciple(null);
assertEquals("The result holds the same value configDao did", "cn=cloudstack,cn=users,dc=cloudstack,dc=org",result);
}
@Test
public void getTrustStorePasswordResopnds() throws Exception {
// We have a ConfigDao with a value for truststore password
overrideConfigValue("ldapTrustStorePassword", "password");
String result = ldapConfiguration.getTrustStorePassword();
assertEquals("The result is password", "password", result);
}
@Test
public void getGroupObject() throws Exception {
String [] groupNames = {"bla", "groupOfUniqueNames", "groupOfNames", "", null};
for (String groupObject: groupNames) {
overrideConfigValue("ldapGroupObject", groupObject);
String expectedResult = null;
if(groupObject == null) {
expectedResult = "groupOfUniqueNames";
} else {
expectedResult = groupObject;
};
String result = ldapConfiguration.getGroupObject(null);
assertEquals("testing for " + groupObject, expectedResult, result);
}
}
}

View File

@ -39,6 +39,10 @@ import com.cloud.template.TemplateManager;
import com.cloud.vm.UserVmManager;
import com.cloud.vm.snapshot.VMSnapshotManager;
/**
* @deprecated use the more dynamic ConfigKey
*/
@Deprecated
public enum Config {
// Alert
@ -1814,42 +1818,6 @@ public enum Config {
+ "If it is set to -1, then it means always use single-part upload to upload object to S3. ",
null),
// Ldap
LdapBasedn("Advanced", ManagementServer.class, String.class, "ldap.basedn", null, "Sets the basedn for LDAP", null),
LdapBindPassword("Advanced", ManagementServer.class, String.class, "ldap.bind.password", null, "Sets the bind password for LDAP", null),
LdapBindPrincipal("Advanced", ManagementServer.class, String.class, "ldap.bind.principal", null, "Sets the bind principal for LDAP", null),
LdapEmailAttribute("Advanced", ManagementServer.class, String.class, "ldap.email.attribute", "mail", "Sets the email attribute used within LDAP", null),
LdapFirstnameAttribute(
"Advanced",
ManagementServer.class,
String.class,
"ldap.firstname.attribute",
"givenname",
"Sets the firstname attribute used within LDAP",
null),
LdapLastnameAttribute("Advanced", ManagementServer.class, String.class, "ldap.lastname.attribute", "sn", "Sets the lastname attribute used within LDAP", null),
LdapUsernameAttribute("Advanced", ManagementServer.class, String.class, "ldap.username.attribute", "uid", "Sets the username attribute used within LDAP", null),
LdapUserObject("Advanced", ManagementServer.class, String.class, "ldap.user.object", "inetOrgPerson", "Sets the object type of users within LDAP", null),
LdapSearchGroupPrinciple(
"Advanced",
ManagementServer.class,
String.class,
"ldap.search.group.principle",
null,
"Sets the principle of the group that users must be a member of",
null),
LdapTrustStore("Advanced", ManagementServer.class, String.class, "ldap.truststore", null, "Sets the path to the truststore to use for SSL", null),
LdapTrustStorePassword("Advanced", ManagementServer.class, String.class, "ldap.truststore.password", null, "Sets the password for the truststore", null),
LdapGroupObject("Advanced", ManagementServer.class, String.class, "ldap.group.object", "groupOfUniqueNames", "Sets the object type of groups within LDAP", null),
LdapGroupUniqueMemberAttribute(
"Advanced",
ManagementServer.class,
String.class,
"ldap.group.user.uniquemember",
"uniquemember",
"Sets the attribute for uniquemembers within a group",
null),
// VMSnapshots
VMSnapshotMax("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.max", "10", "Maximum vm snapshots for a vm", null),
VMSnapshotCreateWait("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.create.wait", "1800", "In second, timeout for create vm snapshot", null),
@ -1979,17 +1947,6 @@ public enum Config {
_scope = ConfigKey.Scope.Global.toString();
}
private Config(String category, Class<?> componentClass, Class<?> type, String name, String defaultValue, String description, String range, String scope) {
_category = category;
_componentClass = componentClass;
_type = type;
_name = name;
_defaultValue = defaultValue;
_description = description;
_range = range;
_scope = scope;
}
public String getCategory() {
return _category;
}
@ -2010,10 +1967,6 @@ public enum Config {
return _type;
}
public Class<?> getComponentClass() {
return _componentClass;
}
public String getScope() {
return _scope;
}
@ -2081,8 +2034,4 @@ public enum Config {
}
return categories;
}
public static List<Config> getConfigListByScope(String scope) {
return s_scopeLevelConfigsMap.get(scope);
}
}

View File

@ -131,8 +131,10 @@ import com.cloud.dc.dao.VlanDao;
import com.cloud.deploy.DataCenterDeployment;
import com.cloud.deploy.DeploymentClusterPlanner;
import com.cloud.domain.Domain;
import com.cloud.domain.DomainDetailVO;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.domain.dao.DomainDetailsDao;
import com.cloud.event.ActionEvent;
import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventUtils;
@ -327,6 +329,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
@Inject
AccountDetailsDao _accountDetailsDao;
@Inject
DomainDetailsDao _domainDetailsDao;
@Inject
PrimaryDataStoreDao _storagePoolDao;
@Inject
NicSecondaryIpDao _nicSecondaryIpDao;
@ -548,6 +552,21 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
_imageStoreDetailsDao.addDetail(resourceId, name, value, true);
break;
case Domain:
final DomainVO domain = _domainDao.findById(resourceId);
if (domain == null) {
throw new InvalidParameterValueException("unable to find domain by id " + resourceId);
}
DomainDetailVO domainDetailVO = _domainDetailsDao.findDetail(resourceId, name);
if (domainDetailVO == null) {
domainDetailVO = new DomainDetailVO(resourceId, name, value);
_domainDetailsDao.persist(domainDetailVO);
} else {
domainDetailVO.setValue(value);
_domainDetailsDao.update(domainDetailVO.getId(), domainDetailVO);
}
break;
default:
throw new InvalidParameterValueException("Scope provided is invalid");
}
@ -655,6 +674,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
final Long storagepoolId = cmd.getStoragepoolId();
final Long accountId = cmd.getAccountId();
final Long imageStoreId = cmd.getImageStoreId();
final Long domainId = cmd.getDomainId();
CallContext.current().setEventDetails(" Name: " + name + " New Value: " + (name.toLowerCase().contains("password") ? "*****" : value == null ? "" : value));
// check if config value exists
final ConfigurationVO config = _configDao.findByName(name);
@ -700,6 +720,11 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
id = accountId;
paramCountCheck++;
}
if (domainId != null) {
scope = ConfigKey.Scope.Domain.toString();
id = domainId;
paramCountCheck++;
}
if (storagepoolId != null) {
scope = ConfigKey.Scope.StoragePool.toString();
id = storagepoolId;

View File

@ -1686,6 +1686,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
final Long clusterId = cmd.getClusterId();
final Long storagepoolId = cmd.getStoragepoolId();
final Long accountId = cmd.getAccountId();
final Long domainId = cmd.getDomainId();
final Long imageStoreId = cmd.getImageStoreId();
String scope = null;
Long id = null;
@ -1706,6 +1707,11 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
id = accountId;
paramCountCheck++;
}
if (domainId != null) {
scope = ConfigKey.Scope.Domain.toString();
id = domainId;
paramCountCheck++;
}
if (storagepoolId != null) {
scope = ConfigKey.Scope.StoragePool.toString();
id = storagepoolId;

View File

@ -215,4 +215,6 @@ public interface AccountManager extends AccountService, Configurable{
"false",
"This parameter allows the users to enable or disable of showing secret key as a part of response for various APIs. By default it is set to false.",
true);
boolean moveUser(long id, Long domainId, long accountId);
}

View File

@ -1702,17 +1702,32 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
@ActionEvent(eventType = EventTypes.EVENT_USER_MOVE, eventDescription = "moving User to a new account")
public boolean moveUser(MoveUserCmd cmd) {
UserVO user = getValidUserVO(cmd.getId());
final Long id = cmd.getId();
UserVO user = getValidUserVO(id);
Account oldAccount = _accountDao.findById(user.getAccountId());
checkAccountAndAccess(user, oldAccount);
long domainId = oldAccount.getDomainId();
long newAccountId = getNewAccountId(cmd, domainId);
long newAccountId = getNewAccountId(domainId, cmd.getAccountName(), cmd.getAccountId());
return moveUser(user, newAccountId);
}
public boolean moveUser(long id, Long domainId, long accountId) {
UserVO user = getValidUserVO(id);
Account oldAccount = _accountDao.findById(user.getAccountId());
checkAccountAndAccess(user, oldAccount);
Account newAccount = _accountDao.findById(accountId);
checkIfNotMovingAcrossDomains(domainId, newAccount);
return moveUser(user , accountId);
}
private boolean moveUser(UserVO user, long newAccountId) {
if(newAccountId == user.getAccountId()) {
// could do a not silent fail but the objective of the user is reached
return true; // no need to create a new user object for this user
}
return Transaction.execute(new TransactionCallback<Boolean>() {
@Override
public Boolean doInTransaction(TransactionStatus status) {
@ -1721,34 +1736,37 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
user.setUuid(UUID.randomUUID().toString());
_userDao.update(user.getId(),user);
newUser.setAccountId(newAccountId);
boolean success = _userDao.remove(cmd.getId());
boolean success = _userDao.remove(user.getId());
UserVO persisted = _userDao.persist(newUser);
return success && persisted.getUuid().equals(user.getExternalEntity());
}
});
}
private long getNewAccountId(MoveUserCmd cmd, long domainId) {
private long getNewAccountId(long domainId, String accountName, Long accountId) {
Account newAccount = null;
if (StringUtils.isNotBlank(cmd.getAccountName())) {
if (StringUtils.isNotBlank(accountName)) {
if(s_logger.isDebugEnabled()) {
s_logger.debug("Getting id for account by name '" + cmd.getAccountName() + "' in domain " + domainId);
s_logger.debug("Getting id for account by name '" + accountName + "' in domain " + domainId);
}
newAccount = _accountDao.findEnabledAccount(cmd.getAccountName(), domainId);
newAccount = _accountDao.findEnabledAccount(accountName, domainId);
}
if (newAccount == null && cmd.getAccountId() != null) {
newAccount = _accountDao.findById(cmd.getAccountId());
if (newAccount == null && accountId != null) {
newAccount = _accountDao.findById(accountId);
}
if (newAccount == null) {
throw new CloudRuntimeException("no account name or account id. this should have been caught before this point");
}
long newAccountId = newAccount.getAccountId();
checkIfNotMovingAcrossDomains(domainId, newAccount);
return newAccount.getAccountId();
}
private void checkIfNotMovingAcrossDomains(long domainId, Account newAccount) {
if(newAccount.getDomainId() != domainId) {
// not in scope
throw new InvalidParameterValueException("moving a user from an account in one domain to an account in annother domain is not supported!");
}
return newAccountId;
}
private void checkAccountAndAccess(UserVO user, Account account) {

View File

@ -123,7 +123,13 @@ public class MockAccountManagerImpl extends ManagerBase implements Manager, Acco
return false;
}
@Override public boolean moveUser(MoveUserCmd moveUserCmd) {
@Override
public boolean moveUser(MoveUserCmd moveUserCmd) {
return false;
}
@Override
public boolean moveUser(long id, Long domainId, long accountId) {
return false;
}

View File

@ -19,34 +19,6 @@ package org.apache.cloudstack.networkoffering;
import java.io.IOException;
import com.cloud.network.dao.FirewallRulesDcidrsDaoImpl;
import com.cloud.storage.StorageManager;
import org.mockito.Mockito;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.affinity.AffinityGroupService;
import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.framework.config.ConfigDepot;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.region.PortableIpDaoImpl;
import org.apache.cloudstack.region.PortableIpRangeDaoImpl;
import org.apache.cloudstack.region.dao.RegionDaoImpl;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDaoImpl;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDaoImpl;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl;
import org.apache.cloudstack.test.utils.SpringUtils;
import com.cloud.agent.AgentManager;
import com.cloud.alert.AlertManager;
import com.cloud.api.query.dao.UserAccountJoinDaoImpl;
@ -67,6 +39,7 @@ import com.cloud.dc.dao.PodVlanDaoImpl;
import com.cloud.dc.dao.PodVlanMapDaoImpl;
import com.cloud.dc.dao.VlanDaoImpl;
import com.cloud.domain.dao.DomainDaoImpl;
import com.cloud.domain.dao.DomainDetailsDao;
import com.cloud.event.dao.UsageEventDaoImpl;
import com.cloud.host.dao.HostDaoImpl;
import com.cloud.host.dao.HostDetailsDaoImpl;
@ -79,6 +52,7 @@ import com.cloud.network.StorageNetworkManager;
import com.cloud.network.dao.AccountGuestVlanMapDaoImpl;
import com.cloud.network.dao.FirewallRulesCidrsDaoImpl;
import com.cloud.network.dao.FirewallRulesDaoImpl;
import com.cloud.network.dao.FirewallRulesDcidrsDaoImpl;
import com.cloud.network.dao.IPAddressDaoImpl;
import com.cloud.network.dao.LoadBalancerDaoImpl;
import com.cloud.network.dao.NetworkDao;
@ -107,6 +81,7 @@ import com.cloud.server.ConfigurationServer;
import com.cloud.server.ManagementService;
import com.cloud.service.dao.ServiceOfferingDaoImpl;
import com.cloud.service.dao.ServiceOfferingDetailsDaoImpl;
import com.cloud.storage.StorageManager;
import com.cloud.storage.dao.DiskOfferingDaoImpl;
import com.cloud.storage.dao.SnapshotDaoImpl;
import com.cloud.storage.dao.StoragePoolDetailsDaoImpl;
@ -123,6 +98,30 @@ import com.cloud.vm.dao.NicDaoImpl;
import com.cloud.vm.dao.NicSecondaryIpDaoImpl;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDaoImpl;
import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.affinity.AffinityGroupService;
import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.framework.config.ConfigDepot;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.region.PortableIpDaoImpl;
import org.apache.cloudstack.region.PortableIpRangeDaoImpl;
import org.apache.cloudstack.region.dao.RegionDaoImpl;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDaoImpl;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDaoImpl;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl;
import org.apache.cloudstack.test.utils.SpringUtils;
import org.mockito.Mockito;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
@Configuration
@ComponentScan(basePackageClasses = {AccountVlanMapDaoImpl.class, DomainVlanMapDaoImpl.class, VolumeDaoImpl.class, HostPodDaoImpl.class, DomainDaoImpl.class, ServiceOfferingDaoImpl.class,
@ -320,6 +319,11 @@ public class
return Mockito.mock(AccountDetailsDao.class);
}
@Bean
public DomainDetailsDao domainDetailsDao() {
return Mockito.mock(DomainDetailsDao.class);
}
@Bean
public DataStoreManager dataStoreManager() {
return Mockito.mock(DataStoreManager.class);

View File

@ -457,6 +457,15 @@
}
}
},
tabFilter: function(args) {
var hiddenTabs = [];
if(!isAdmin()) {
hiddenTabs.push('settings');
}
return hiddenTabs;
},
tabs: {
details: {
title: 'label.details',
@ -638,36 +647,6 @@
domainObj["vmTotal"] = totalVMs;
domainObj["volumeTotal"] = totalVolumes;
/* $.ajax({
url: createURL("listVirtualMachines&details=min&domainid=" + domainObj.id),
async: false,
dataType: "json",
success: function(json) {
var items = json.listvirtualmachinesresponse.virtualmachine;
var total;
if (items != null)
total = items.length;
else
total = 0;
domainObj["vmTotal"] = total;
}
});
$.ajax({
url: createURL("listVolumes&domainid=" + domainObj.id),
async: false,
dataType: "json",
success: function(json) {
var items = json.listvolumesresponse.volume;
var total;
if (items != null)
total = items.length;
else
total = 0;
domainObj["volumeTotal"] = total;
}
});*/
$.ajax({
url: createURL("listResourceLimits&domainid=" + domainObj.id),
async: false,
@ -722,7 +701,58 @@
actionFilter: domainActionfilter
});
}
},
// Granular settings for domains
settings: {
title: 'label.settings',
custom: cloudStack.uiCustom.granularSettings({
dataProvider: function(args) {
$.ajax({
url: createURL('listConfigurations&domainid=' + args.context.domains[0].id),
data: listViewDataProvider(args, {}, { searchBy: 'name' }),
success: function(json) {
args.response.success({
data: json.listconfigurationsresponse.configuration
});
},
error: function(json) {
args.response.error(parseXMLHttpResponse(json));
}
});
},
actions: {
edit: function(args) {
// call updateDomainLevelParameters
var data = {
name: args.data.jsonObj.name,
value: args.data.value
};
$.ajax({
url: createURL('updateConfiguration&domainid=' + args.context.domains[0].id),
data: data,
success: function(json) {
var item = json.updateconfigurationresponse.configuration;
args.response.success({
data: item
});
},
error: function(json) {
args.response.error(parseXMLHttpResponse(json));
}
});
}
}
})
}
}
},
labelField: 'name',