unlink an ldap domain (#11962)

Co-authored-by: Daan Hoogland <dahn@apache.org>
Co-authored-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Co-authored-by: Suresh Kumar Anaparti <sureshkumar.anaparti@gmail.com>
This commit is contained in:
dahn 2025-12-17 13:04:06 +01:00 committed by GitHub
parent 53a39d3ff7
commit 124fcde59c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 119 additions and 13 deletions

View File

@ -215,5 +215,11 @@
<artifactId>commons-io</artifactId> <artifactId>commons-io</artifactId>
<version>${cs.commons-io.version}</version> <version>${cs.commons-io.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-api</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -51,14 +51,10 @@ public class LinkDomainToLdapCmd extends BaseCmd {
@Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, required = true, description = "type of the ldap name. GROUP or OU") @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, required = true, description = "type of the ldap name. GROUP or OU")
private String type; private String type;
@Parameter(name = ApiConstants.LDAP_DOMAIN, type = CommandType.STRING, required = false, description = "name of the group or OU in LDAP") @Parameter(name = ApiConstants.LDAP_DOMAIN, type = CommandType.STRING, required = true, description = "name of the group or OU in LDAP")
private String ldapDomain; private String ldapDomain;
@Deprecated @Parameter(name = ApiConstants.ADMIN, type = CommandType.STRING, description = "domain admin username in LDAP ")
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = false, description = "name of the group or OU in LDAP")
private String name;
@Parameter(name = ApiConstants.ADMIN, type = CommandType.STRING, required = false, description = "domain admin username in LDAP ")
private String admin; private String admin;
@Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.INTEGER, required = true, description = "Type of the account to auto import. Specify 0 for user and 2 for " + @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.INTEGER, required = true, description = "Type of the account to auto import. Specify 0 for user and 2 for " +
@ -77,7 +73,7 @@ public class LinkDomainToLdapCmd extends BaseCmd {
} }
public String getLdapDomain() { public String getLdapDomain() {
return ldapDomain == null ? name : ldapDomain; return ldapDomain;
} }
public String getAdmin() { public String getAdmin() {
@ -98,7 +94,7 @@ public class LinkDomainToLdapCmd extends BaseCmd {
try { try {
ldapUser = _ldapManager.getUser(admin, type, getLdapDomain(), domainId); ldapUser = _ldapManager.getUser(admin, type, getLdapDomain(), domainId);
} catch (NoLdapUserMatchingQueryException e) { } catch (NoLdapUserMatchingQueryException e) {
logger.debug("no ldap user matching username " + admin + " in the given group/ou", e); logger.debug("no ldap user matching username {} in the given group/ou", admin, e);
} }
if (ldapUser != null && !ldapUser.isDisabled()) { if (ldapUser != null && !ldapUser.isDisabled()) {
Account account = _accountService.getActiveAccountByName(admin, domainId); Account account = _accountService.getActiveAccountByName(admin, domainId);
@ -115,7 +111,7 @@ public class LinkDomainToLdapCmd extends BaseCmd {
logger.debug("an account with name {} already exists in the domain {} with id {}", admin, _domainService.getDomain(domainId), domainId); logger.debug("an account with name {} already exists in the domain {} with id {}", admin, _domainService.getDomain(domainId), domainId);
} }
} else { } else {
logger.debug("ldap user with username "+admin+" is disabled in the given group/ou"); logger.debug("ldap user with username {} is disabled in the given group/ou", admin);
} }
} }
response.setObjectName("LinkDomainToLdap"); response.setObjectName("LinkDomainToLdap");

View File

@ -0,0 +1,69 @@
/*
* 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.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.user.Account;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.ldap.LdapManager;
import javax.inject.Inject;
@APICommand(name = "unlinkDomainFromLdap", description = "remove the linkage of a Domain to a group or OU in ldap",
responseObject = SuccessResponse.class, since = "4.23.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class UnlinkDomainFromLdapCmd extends BaseCmd {
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = true, entityType = DomainResponse.class,
description = "The ID of the Domain which has to be unlinked from LDAP.")
private Long domainId;
@Inject
private LdapManager _ldapManager;
public Long getDomainId() {
return domainId;
}
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
boolean rc = _ldapManager.unlinkDomainFromLdap(this);
SuccessResponse response = new SuccessResponse(getCommandName());
response.setSuccess(rc);
if (rc) {
response.setDisplayText("Domain unlinked from LDAP successfully");
} else {
response.setDisplayText("Failed to unlink domain from LDAP");
}
setResponseObject(response);
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -23,6 +23,7 @@ import org.apache.cloudstack.api.command.LdapDeleteConfigurationCmd;
import org.apache.cloudstack.api.command.LdapListConfigurationCmd; import org.apache.cloudstack.api.command.LdapListConfigurationCmd;
import org.apache.cloudstack.api.command.LinkAccountToLdapCmd; import org.apache.cloudstack.api.command.LinkAccountToLdapCmd;
import org.apache.cloudstack.api.command.LinkDomainToLdapCmd; import org.apache.cloudstack.api.command.LinkDomainToLdapCmd;
import org.apache.cloudstack.api.command.UnlinkDomainFromLdapCmd;
import org.apache.cloudstack.api.response.LdapConfigurationResponse; import org.apache.cloudstack.api.response.LdapConfigurationResponse;
import org.apache.cloudstack.api.response.LdapUserResponse; import org.apache.cloudstack.api.response.LdapUserResponse;
@ -34,7 +35,7 @@ import org.apache.cloudstack.api.response.LinkDomainToLdapResponse;
public interface LdapManager extends PluggableService { public interface LdapManager extends PluggableService {
enum LinkType { GROUP, OU;} enum LinkType { GROUP, OU}
LdapConfigurationResponse addConfiguration(final LdapAddConfigurationCmd cmd) throws InvalidParameterValueException; LdapConfigurationResponse addConfiguration(final LdapAddConfigurationCmd cmd) throws InvalidParameterValueException;
@ -69,6 +70,8 @@ public interface LdapManager extends PluggableService {
LinkDomainToLdapResponse linkDomainToLdap(LinkDomainToLdapCmd cmd); LinkDomainToLdapResponse linkDomainToLdap(LinkDomainToLdapCmd cmd);
boolean unlinkDomainFromLdap(UnlinkDomainFromLdapCmd cmd);
LdapTrustMapVO getDomainLinkedToLdap(long domainId); LdapTrustMapVO getDomainLinkedToLdap(long domainId);
List<LdapTrustMapVO> getDomainLinkage(long domainId); List<LdapTrustMapVO> getDomainLinkage(long domainId);

View File

@ -43,6 +43,7 @@ import org.apache.cloudstack.api.command.LdapListUsersCmd;
import org.apache.cloudstack.api.command.LdapUserSearchCmd; import org.apache.cloudstack.api.command.LdapUserSearchCmd;
import org.apache.cloudstack.api.command.LinkAccountToLdapCmd; import org.apache.cloudstack.api.command.LinkAccountToLdapCmd;
import org.apache.cloudstack.api.command.LinkDomainToLdapCmd; import org.apache.cloudstack.api.command.LinkDomainToLdapCmd;
import org.apache.cloudstack.api.command.UnlinkDomainFromLdapCmd;
import org.apache.cloudstack.api.response.LdapConfigurationResponse; import org.apache.cloudstack.api.response.LdapConfigurationResponse;
import org.apache.cloudstack.api.response.LdapUserResponse; import org.apache.cloudstack.api.response.LdapUserResponse;
import org.apache.cloudstack.api.response.LinkAccountToLdapResponse; import org.apache.cloudstack.api.response.LinkAccountToLdapResponse;
@ -292,7 +293,7 @@ public class LdapManagerImpl extends ComponentLifecycleBase implements LdapManag
@Override @Override
public List<Class<?>> getCommands() { public List<Class<?>> getCommands() {
final List<Class<?>> cmdList = new ArrayList<Class<?>>(); final List<Class<?>> cmdList = new ArrayList<>();
cmdList.add(LdapUserSearchCmd.class); cmdList.add(LdapUserSearchCmd.class);
cmdList.add(LdapListUsersCmd.class); cmdList.add(LdapListUsersCmd.class);
cmdList.add(LdapAddConfigurationCmd.class); cmdList.add(LdapAddConfigurationCmd.class);
@ -304,6 +305,7 @@ public class LdapManagerImpl extends ComponentLifecycleBase implements LdapManag
cmdList.add(LDAPRemoveCmd.class); cmdList.add(LDAPRemoveCmd.class);
cmdList.add(LinkDomainToLdapCmd.class); cmdList.add(LinkDomainToLdapCmd.class);
cmdList.add(LinkAccountToLdapCmd.class); cmdList.add(LinkAccountToLdapCmd.class);
cmdList.add(UnlinkDomainFromLdapCmd.class);
return cmdList; return cmdList;
} }
@ -393,7 +395,7 @@ public class LdapManagerImpl extends ComponentLifecycleBase implements LdapManag
final boolean listAll = cmd.listAll(); final boolean listAll = cmd.listAll();
final Long id = cmd.getId(); final Long id = cmd.getId();
final Pair<List<LdapConfigurationVO>, Integer> result = _ldapConfigurationDao.searchConfigurations(id, hostname, port, domainId, listAll); final Pair<List<LdapConfigurationVO>, Integer> result = _ldapConfigurationDao.searchConfigurations(id, hostname, port, domainId, listAll);
return new Pair<List<? extends LdapConfigurationVO>, Integer>(result.first(), result.second()); return new Pair<>(result.first(), result.second());
} }
@Override @Override
@ -423,6 +425,11 @@ public class LdapManagerImpl extends ComponentLifecycleBase implements LdapManag
return linkDomainToLdap(cmd.getDomainId(),cmd.getType(), ldapDomain,cmd.getAccountType()); return linkDomainToLdap(cmd.getDomainId(),cmd.getType(), ldapDomain,cmd.getAccountType());
} }
@Override
public boolean unlinkDomainFromLdap(UnlinkDomainFromLdapCmd cmd) {
return unlinkDomainFromLdap(cmd.getDomainId());
}
private LinkDomainToLdapResponse linkDomainToLdap(Long domainId, String type, String name, Account.Type accountType) { private LinkDomainToLdapResponse linkDomainToLdap(Long domainId, String type, String name, Account.Type accountType) {
Validate.notNull(type, "type cannot be null. It should either be GROUP or OU"); Validate.notNull(type, "type cannot be null. It should either be GROUP or OU");
Validate.notNull(domainId, "domainId cannot be null."); Validate.notNull(domainId, "domainId cannot be null.");
@ -442,6 +449,15 @@ public class LdapManagerImpl extends ComponentLifecycleBase implements LdapManag
return response; return response;
} }
private boolean unlinkDomainFromLdap(Long domainId) {
LdapTrustMapVO vo = _ldapTrustMapDao.findByDomainId(domainId);
if (vo != null) {
removeTrustmap(vo);
return true;
}
return false;
}
@Override @Override
public LdapTrustMapVO getDomainLinkedToLdap(long domainId){ public LdapTrustMapVO getDomainLinkedToLdap(long domainId){
return _ldapTrustMapDao.findByDomainId(domainId); return _ldapTrustMapDao.findByDomainId(domainId);

View File

@ -1452,6 +1452,7 @@
"label.lbruleid": "Load balancer ID", "label.lbruleid": "Load balancer ID",
"label.lbtype": "Load balancer type", "label.lbtype": "Load balancer type",
"label.ldap": "LDAP", "label.ldap": "LDAP",
"label.ldapdomain": "LDAP Domain",
"label.ldap.configuration": "LDAP Configuration", "label.ldap.configuration": "LDAP Configuration",
"label.ldap.group.name": "LDAP Group", "label.ldap.group.name": "LDAP Group",
"label.level": "Level", "label.level": "Level",
@ -2587,6 +2588,7 @@
"label.undefined": "Undefined", "label.undefined": "Undefined",
"label.unit": "Usage unit", "label.unit": "Usage unit",
"label.unknown": "Unknown", "label.unknown": "Unknown",
"label.unlink.domain.from.ldap": "Unlink the Domain from LDAP",
"label.unlimited": "Unlimited", "label.unlimited": "Unlimited",
"label.unmanaged": "Unmanaged", "label.unmanaged": "Unmanaged",
"label.unmanage.instance": "Unmanage Instance", "label.unmanage.instance": "Unmanage Instance",

View File

@ -144,7 +144,7 @@ export default {
docHelp: 'adminguide/accounts.html#using-an-ldap-server-for-user-authentication', docHelp: 'adminguide/accounts.html#using-an-ldap-server-for-user-authentication',
listView: true, listView: true,
dataView: true, dataView: true,
args: ['type', 'domainid', 'name', 'accounttype', 'admin'], args: ['type', 'domainid', 'ldapdomain', 'accounttype', 'admin'],
mapping: { mapping: {
type: { type: {
options: ['GROUP', 'OU'] options: ['GROUP', 'OU']
@ -157,6 +157,20 @@ export default {
} }
} }
}, },
{
api: 'unlinkDomainFromLdap',
icon: 'ArrowsAltOutlined',
label: 'label.unlink.domain.from.ldap',
docHelp: 'adminguide/accounts.html#using-an-ldap-server-for-user-authentication',
listView: true,
dataView: true,
args: ['domainid'],
mapping: {
domainid: {
value: (record) => { return record.id }
}
}
},
{ {
api: 'deleteDomain', api: 'deleteDomain',
icon: 'delete-outlined', icon: 'delete-outlined',