use of com.zimbra.cs.ldap.LdapException in project zm-mailbox by Zimbra.
the class LdapProvisioning method renameAccount.
@Override
public void renameAccount(String zimbraId, String newName) throws ServiceException {
newName = IDNUtil.toAsciiEmail(newName);
validEmailAddress(newName);
ZLdapContext zlc = null;
Account acct = getAccountById(zimbraId, zlc, true);
// prune cache
accountCache.remove(acct);
LdapEntry entry = (LdapEntry) acct;
if (acct == null)
throw AccountServiceException.NO_SUCH_ACCOUNT(zimbraId);
String oldEmail = acct.getName();
boolean domainChanged = false;
Account oldAccount = acct;
try {
zlc = LdapClient.getContext(LdapServerType.MASTER, LdapUsage.RENAME_ACCOUNT);
String oldDn = entry.getDN();
String[] parts = EmailUtil.getLocalPartAndDomain(oldEmail);
String oldLocal = parts[0];
String oldDomain = parts[1];
newName = newName.toLowerCase().trim();
parts = EmailUtil.getLocalPartAndDomain(newName);
if (parts == null) {
throw ServiceException.INVALID_REQUEST("bad value for newName", null);
}
String newLocal = parts[0];
String newDomain = parts[1];
Domain domain = getDomainByAsciiName(newDomain, zlc);
if (domain == null) {
throw AccountServiceException.NO_SUCH_DOMAIN(newDomain);
}
domainChanged = !newDomain.equals(oldDomain);
if (domainChanged) {
validate(ProvisioningValidator.RENAME_ACCOUNT, newName, acct.getMultiAttr(Provisioning.A_objectClass, false), acct.getAttrs(false));
validate(ProvisioningValidator.RENAME_ACCOUNT_CHECK_DOMAIN_COS_AND_FEATURE, newName, acct.getAttrs(false));
// make sure the new domain is a local domain
if (!domain.isLocal()) {
throw ServiceException.INVALID_REQUEST("domain type must be local", null);
}
}
String newDn = mDIT.accountDNRename(oldDn, newLocal, domain.getName());
boolean dnChanged = (!newDn.equals(oldDn));
Map<String, Object> newAttrs = acct.getAttrs(false);
if (dnChanged) {
// uid will be changed during renameEntry, so no need to modify it
// OpenLDAP is OK modifying it, as long as it matches the new DN, but
// InMemoryDirectoryServer does not like it.
newAttrs.remove(Provisioning.A_uid);
} else {
newAttrs.put(Provisioning.A_uid, newLocal);
}
newAttrs.put(Provisioning.A_zimbraMailDeliveryAddress, newName);
if (oldEmail.equals(newAttrs.get(Provisioning.A_zimbraPrefFromAddress))) {
newAttrs.put(Provisioning.A_zimbraPrefFromAddress, newName);
}
ReplaceAddressResult replacedMails = replaceMailAddresses(acct, Provisioning.A_mail, oldEmail, newName);
if (replacedMails.newAddrs().length == 0) {
// Set mail to newName if the account currently does not have a mail
newAttrs.put(Provisioning.A_mail, newName);
} else {
newAttrs.put(Provisioning.A_mail, replacedMails.newAddrs());
}
ReplaceAddressResult replacedAliases = replaceMailAddresses(acct, Provisioning.A_zimbraMailAlias, oldEmail, newName);
if (replacedAliases.newAddrs().length > 0) {
newAttrs.put(Provisioning.A_zimbraMailAlias, replacedAliases.newAddrs());
String newDomainDN = mDIT.domainToAccountSearchDN(newDomain);
String[] aliasNewAddrs = replacedAliases.newAddrs();
// (if domain also got changed)
if (domainChanged && addressExistsUnderDN(zlc, newDomainDN, aliasNewAddrs)) {
throw AccountServiceException.ALIAS_EXISTS(Arrays.toString(aliasNewAddrs));
}
// it won't be caught by the above check, do a separate check.
for (int i = 0; i < aliasNewAddrs.length; i++) {
if (newName.equalsIgnoreCase(aliasNewAddrs[i])) {
throw AccountServiceException.ACCOUNT_EXISTS(newName);
}
}
}
ReplaceAddressResult replacedAllowAddrForDelegatedSender = replaceMailAddresses(acct, Provisioning.A_zimbraPrefAllowAddressForDelegatedSender, oldEmail, newName);
if (replacedAllowAddrForDelegatedSender.newAddrs().length > 0) {
newAttrs.put(Provisioning.A_zimbraPrefAllowAddressForDelegatedSender, replacedAllowAddrForDelegatedSender.newAddrs());
}
if (newAttrs.get(Provisioning.A_displayName) == null && oldLocal.equals(newAttrs.get(Provisioning.A_cn)))
newAttrs.put(Provisioning.A_cn, newLocal);
if (dnChanged) {
zlc.renameEntry(oldDn, newDn);
// re-get the acct object, make sure we don't get it from cache
// Note: this account object contains the old address, it should never
// be cached
acct = getAccountByQuery(mDIT.mailBranchBaseDN(), filterFactory.accountById(zimbraId), zlc, true);
if (acct == null) {
throw ServiceException.FAILURE("cannot find account by id after modrdn", null);
}
}
// rename the account and all it's renamed aliases to the new name in all
// distribution lists. Doesn't throw exceptions, just logs
renameAddressesInAllDistributionLists(oldEmail, newName, replacedAliases);
// doesn't throw exceptions, just logs
if (domainChanged) {
moveAliases(zlc, replacedAliases, newDomain, null, oldDn, newDn, oldDomain, newDomain);
}
modifyLdapAttrs(acct, zlc, newAttrs);
// re-get the account again, now attrs contains new addrs
acct = getAccountByQuery(mDIT.mailBranchBaseDN(), filterFactory.accountById(zimbraId), zlc, true);
if (acct == null) {
throw ServiceException.FAILURE("cannot find account by id after modrdn", null);
}
removeExternalAddrsFromAllDynamicGroups(acct.getAllAddrsSet(), zlc);
} catch (LdapEntryAlreadyExistException nabe) {
throw AccountServiceException.ACCOUNT_EXISTS(newName);
} catch (LdapException e) {
throw e;
} catch (AccountServiceException e) {
throw e;
} catch (ServiceException e) {
throw ServiceException.FAILURE("unable to rename account: " + newName, e);
} finally {
LdapClient.closeContext(zlc);
// prune cache
accountCache.remove(oldAccount);
}
// reload it to cache using the master, bug 45736
Account renamedAcct = getAccountById(zimbraId, null, true);
if (domainChanged) {
PermissionCache.invalidateCache(renamedAcct);
}
}
use of com.zimbra.cs.ldap.LdapException in project zm-mailbox by Zimbra.
the class LdapProvisioning method createAlwaysOnCluster.
@Override
public AlwaysOnCluster createAlwaysOnCluster(String name, Map<String, Object> clusterAttrs) throws ServiceException {
name = name.toLowerCase().trim();
CallbackContext callbackContext = new CallbackContext(CallbackContext.Op.CREATE);
AttributeManager.getInstance().preModify(clusterAttrs, null, callbackContext, true);
ZLdapContext zlc = null;
try {
zlc = LdapClient.getContext(LdapServerType.MASTER, LdapUsage.CREATE_SERVER);
ZMutableEntry entry = LdapClient.createMutableEntry();
entry.mapToAttrs(clusterAttrs);
Set<String> ocs = LdapObjectClass.getAlwaysOnClusterObjectClasses(this);
entry.addAttr(A_objectClass, ocs);
String zimbraIdStr = LdapUtil.generateUUID();
entry.setAttr(A_zimbraId, zimbraIdStr);
entry.setAttr(A_zimbraCreateTimestamp, LdapDateUtil.toGeneralizedTime(new Date()));
entry.setAttr(A_cn, name);
String dn = mDIT.alwaysOnClusterNameToDN(name);
entry.setDN(dn);
zlc.createEntry(entry);
AlwaysOnCluster cluster = getAlwaysOnClusterById(zimbraIdStr, zlc, true);
AttributeManager.getInstance().postModify(clusterAttrs, cluster, callbackContext);
return cluster;
} catch (LdapEntryAlreadyExistException nabe) {
throw AccountServiceException.ALWAYSONCLUSTER_EXISTS(name);
} catch (LdapException e) {
throw e;
} catch (AccountServiceException e) {
throw e;
} catch (ServiceException e) {
throw ServiceException.FAILURE("unable to create akwaysOnCluster: " + name, e);
} finally {
LdapClient.closeContext(zlc);
}
}
use of com.zimbra.cs.ldap.LdapException in project zm-mailbox by Zimbra.
the class LdapProvisioning method addAliasInternal.
private void addAliasInternal(NamedEntry entry, String alias) throws ServiceException {
LdapUsage ldapUsage = null;
String targetDomainName = null;
AliasedEntry aliasedEntry = null;
if (entry instanceof Account) {
aliasedEntry = (AliasedEntry) entry;
targetDomainName = ((Account) entry).getDomainName();
ldapUsage = LdapUsage.ADD_ALIAS_ACCOUNT;
} else if (entry instanceof Group) {
aliasedEntry = (AliasedEntry) entry;
ldapUsage = LdapUsage.ADD_ALIAS_DL;
targetDomainName = ((Group) entry).getDomainName();
} else {
throw ServiceException.FAILURE("invalid entry type for alias", null);
}
alias = alias.toLowerCase().trim();
alias = IDNUtil.toAsciiEmail(alias);
validEmailAddress(alias);
String[] parts = alias.split("@");
String aliasName = parts[0];
String aliasDomain = parts[1];
ZLdapContext zlc = null;
String aliasDn = null;
try {
zlc = LdapClient.getContext(LdapServerType.MASTER, ldapUsage);
Domain domain = getDomainByAsciiName(aliasDomain, zlc);
if (domain == null)
throw AccountServiceException.NO_SUCH_DOMAIN(aliasDomain);
aliasDn = mDIT.aliasDN(((LdapEntry) entry).getDN(), targetDomainName, aliasName, aliasDomain);
// the create and addAttr ideally would be in the same transaction
String aliasUuid = LdapUtil.generateUUID();
String targetEntryId = entry.getId();
try {
zlc.createEntry(aliasDn, "zimbraAlias", new String[] { Provisioning.A_uid, aliasName, Provisioning.A_zimbraId, aliasUuid, Provisioning.A_zimbraCreateTimestamp, LdapDateUtil.toGeneralizedTime(new Date()), Provisioning.A_zimbraAliasTargetId, targetEntryId });
} catch (LdapEntryAlreadyExistException e) {
/*
* check if the alias is a dangling alias. If so remove the dangling alias
* and create a new one.
*/
ZAttributes attrs = helper.getAttributes(zlc, aliasDn);
// see if the entry is an alias
if (!isEntryAlias(attrs))
throw e;
Alias aliasEntry = makeAlias(aliasDn, attrs);
NamedEntry targetEntry = searchAliasTarget(aliasEntry, false);
if (targetEntry == null) {
// remove the dangling alias
try {
removeAliasInternal(null, alias);
} catch (ServiceException se) {
// ignore
}
// try creating the alias again
zlc.createEntry(aliasDn, "zimbraAlias", new String[] { Provisioning.A_uid, aliasName, Provisioning.A_zimbraId, aliasUuid, Provisioning.A_zimbraCreateTimestamp, LdapDateUtil.toGeneralizedTime(new Date()), Provisioning.A_zimbraAliasTargetId, targetEntryId });
} else if (targetEntryId.equals(targetEntry.getId())) {
// the alias target points to this account/DL
Set<String> mailAliases = entry.getMultiAttrSet(Provisioning.A_zimbraMailAlias);
Set<String> mails = entry.getMultiAttrSet(Provisioning.A_mail);
if (mailAliases != null && mailAliases.contains(alias) && mails != null && mails.contains(alias)) {
throw e;
} else {
ZimbraLog.account.warn("alias entry exists at " + aliasDn + ", but either mail or zimbraMailAlias of the target does not contain " + alias + ", adding " + alias + " to entry " + entry.getName());
}
} else {
// for which the alias is being added for, rethrow the naming exception
throw e;
}
}
HashMap<String, String> attrs = new HashMap<String, String>();
attrs.put("+" + Provisioning.A_zimbraMailAlias, alias);
attrs.put("+" + Provisioning.A_mail, alias);
// UGH
modifyAttrsInternal(entry, zlc, attrs);
removeExternalAddrsFromAllDynamicGroups(aliasedEntry.getAllAddrsSet(), zlc);
} catch (LdapEntryAlreadyExistException nabe) {
throw AccountServiceException.ACCOUNT_EXISTS(alias, aliasDn, nabe);
} catch (LdapException e) {
throw e;
} catch (AccountServiceException e) {
throw e;
} catch (ServiceException e) {
throw ServiceException.FAILURE("unable to create alias: " + e.getMessage(), e);
} finally {
LdapClient.closeContext(zlc);
}
}
use of com.zimbra.cs.ldap.LdapException in project zm-mailbox by Zimbra.
the class LdapProvisioning method createSignature.
private Signature createSignature(Account account, String signatureName, Map<String, Object> signatureAttrs, boolean restoring) throws ServiceException {
signatureName = signatureName.trim();
removeAttrIgnoreCase("objectclass", signatureAttrs);
validateSignatureAttrs(signatureAttrs);
LdapEntry ldapEntry = (LdapEntry) (account instanceof LdapEntry ? account : getAccountById(account.getId()));
if (ldapEntry == null)
throw AccountServiceException.NO_SUCH_ACCOUNT(account.getName());
/*
* check if the signature name already exists
*
* We check if the signatureName is the same as the signature on the account.
* For signatures that are in the signature LDAP entries, JNDI will throw
* NameAlreadyBoundException for duplicate names.
*
*/
Signature acctSig = LdapSignature.getAccountSignature(this, account);
if (acctSig != null && signatureName.equalsIgnoreCase(acctSig.getName()))
throw AccountServiceException.SIGNATURE_EXISTS(signatureName);
boolean setAsDefault = false;
List<Signature> existing = getAllSignatures(account);
// If the signature id is supplied with the request, check that it
// is not associated with an existing signature
String signatureId = (String) signatureAttrs.get(Provisioning.A_zimbraSignatureId);
if (signatureId != null) {
for (Signature signature : existing) {
if (signatureId.equals(signature.getAttr(Provisioning.A_zimbraSignatureId))) {
throw AccountServiceException.SIGNATURE_EXISTS(signatureId);
}
}
}
int numSigs = existing.size();
if (numSigs >= account.getLongAttr(A_zimbraSignatureMaxNumEntries, 20))
throw AccountServiceException.TOO_MANY_SIGNATURES();
else if (numSigs == 0)
setAsDefault = true;
account.setCachedData(SIGNATURE_LIST_CACHE_KEY, null);
boolean checkImmutable = !restoring;
CallbackContext callbackContext = new CallbackContext(CallbackContext.Op.CREATE);
callbackContext.setData(DataKey.MAX_SIGNATURE_LEN, String.valueOf(account.getMailSignatureMaxLength()));
AttributeManager.getInstance().preModify(signatureAttrs, null, callbackContext, checkImmutable);
if (signatureId == null) {
signatureId = LdapUtil.generateUUID();
signatureAttrs.put(Provisioning.A_zimbraSignatureId, signatureId);
}
if (acctSig == null) {
// the slot on the account is not occupied, use it
signatureAttrs.put(Provisioning.A_zimbraSignatureName, signatureName);
// pass in setAsDefault as an optimization, since we are updating the account
// entry, we can update the default attr in one LDAP write
LdapSignature.createAccountSignature(this, account, signatureAttrs, setAsDefault);
return LdapSignature.getAccountSignature(this, account);
}
ZLdapContext zlc = null;
try {
zlc = LdapClient.getContext(LdapServerType.MASTER, LdapUsage.CREATE_SIGNATURE);
String dn = getSignatureDn(ldapEntry, signatureName);
ZMutableEntry entry = LdapClient.createMutableEntry();
entry.mapToAttrs(signatureAttrs);
entry.setAttr(A_objectClass, "zimbraSignature");
entry.setAttr(Provisioning.A_zimbraCreateTimestamp, LdapDateUtil.toGeneralizedTime(new Date()));
entry.setDN(dn);
zlc.createEntry(entry);
Signature signature = getSignatureById(account, ldapEntry, signatureId, zlc);
AttributeManager.getInstance().postModify(signatureAttrs, signature, callbackContext);
if (setAsDefault)
setDefaultSignature(account, signatureId);
return signature;
} catch (LdapEntryAlreadyExistException nabe) {
throw AccountServiceException.SIGNATURE_EXISTS(signatureName);
} catch (LdapException e) {
throw e;
} catch (AccountServiceException e) {
throw e;
} catch (ServiceException e) {
throw ServiceException.FAILURE("unable to create signature: " + signatureName, e);
} finally {
LdapClient.closeContext(zlc);
}
}
use of com.zimbra.cs.ldap.LdapException in project zm-mailbox by Zimbra.
the class LdapProvisioning method renameDistributionList.
@Override
public void renameDistributionList(String zimbraId, String newEmail) throws ServiceException {
newEmail = IDNUtil.toAsciiEmail(newEmail);
validEmailAddress(newEmail);
boolean domainChanged = false;
ZLdapContext zlc = null;
try {
zlc = LdapClient.getContext(LdapServerType.MASTER, LdapUsage.RENAME_DISTRIBUTIONLIST);
LdapDistributionList dl = (LdapDistributionList) getDistributionListById(zimbraId, zlc);
if (dl == null) {
throw AccountServiceException.NO_SUCH_DISTRIBUTION_LIST(zimbraId);
}
groupCache.remove(dl);
String oldEmail = dl.getName();
String oldDomain = EmailUtil.getValidDomainPart(oldEmail);
newEmail = newEmail.toLowerCase().trim();
String[] parts = EmailUtil.getLocalPartAndDomain(newEmail);
if (parts == null)
throw ServiceException.INVALID_REQUEST("bad value for newName", null);
String newLocal = parts[0];
String newDomain = parts[1];
domainChanged = !oldDomain.equals(newDomain);
Domain domain = getDomainByAsciiName(newDomain, zlc);
if (domain == null) {
throw AccountServiceException.NO_SUCH_DOMAIN(newDomain);
}
if (domainChanged) {
// make sure the new domain is a local domain
if (!domain.isLocal()) {
throw ServiceException.INVALID_REQUEST("domain type must be local", null);
}
}
Map<String, Object> attrs = new HashMap<String, Object>();
ReplaceAddressResult replacedMails = replaceMailAddresses(dl, Provisioning.A_mail, oldEmail, newEmail);
if (replacedMails.newAddrs().length == 0) {
// Set mail to newName if the account currently does not have a mail
attrs.put(Provisioning.A_mail, newEmail);
} else {
attrs.put(Provisioning.A_mail, replacedMails.newAddrs());
}
ReplaceAddressResult replacedAliases = replaceMailAddresses(dl, Provisioning.A_zimbraMailAlias, oldEmail, newEmail);
if (replacedAliases.newAddrs().length > 0) {
attrs.put(Provisioning.A_zimbraMailAlias, replacedAliases.newAddrs());
String newDomainDN = mDIT.domainToAccountSearchDN(newDomain);
// check up front if any of renamed aliases already exists in the new domain (if domain also got changed)
if (domainChanged && addressExistsUnderDN(zlc, newDomainDN, replacedAliases.newAddrs())) {
throw AccountServiceException.DISTRIBUTION_LIST_EXISTS(newEmail);
}
}
ReplaceAddressResult replacedAllowAddrForDelegatedSender = replaceMailAddresses(dl, Provisioning.A_zimbraPrefAllowAddressForDelegatedSender, oldEmail, newEmail);
if (replacedAllowAddrForDelegatedSender.newAddrs().length > 0) {
attrs.put(Provisioning.A_zimbraPrefAllowAddressForDelegatedSender, replacedAllowAddrForDelegatedSender.newAddrs());
}
String oldDn = dl.getDN();
String newDn = mDIT.distributionListDNRename(oldDn, newLocal, domain.getName());
boolean dnChanged = (!oldDn.equals(newDn));
if (dnChanged) {
// uid will be changed during renameEntry, so no need to modify it
// OpenLDAP is OK modifying it, as long as it matches the new DN, but
// InMemoryDirectoryServer does not like it.
attrs.remove(A_uid);
} else {
/*
* always reset uid to the local part, because in non default DIT the naming RDN might not
* be uid, and ctxt.rename won't change the uid to the new localpart in that case.
*/
attrs.put(A_uid, newLocal);
}
// move over the distribution list entry
if (dnChanged) {
zlc.renameEntry(oldDn, newDn);
}
dl = (LdapDistributionList) getDistributionListById(zimbraId, zlc);
// rename the distribution list and all it's renamed aliases to the new name
// in all distribution lists.
// Doesn't throw exceptions, just logs.
renameAddressesInAllDistributionLists(oldEmail, newEmail, replacedAliases);
// doesn't throw exceptions, just logs
if (domainChanged) {
String newUid = dl.getAttr(Provisioning.A_uid);
moveAliases(zlc, replacedAliases, newDomain, newUid, oldDn, newDn, oldDomain, newDomain);
}
// could fail. So catch service exception here and log error
try {
modifyAttrsInternal(dl, zlc, attrs);
} catch (ServiceException e) {
ZimbraLog.account.error("distribution list renamed to " + newLocal + " but failed to move old name's LDAP attributes", e);
throw e;
}
removeExternalAddrsFromAllDynamicGroups(dl.getAllAddrsSet(), zlc);
} catch (LdapEntryAlreadyExistException nabe) {
throw AccountServiceException.DISTRIBUTION_LIST_EXISTS(newEmail);
} catch (LdapException e) {
throw e;
} catch (AccountServiceException e) {
throw e;
} catch (ServiceException e) {
throw ServiceException.FAILURE("unable to rename distribution list: " + zimbraId, e);
} finally {
LdapClient.closeContext(zlc);
}
if (domainChanged) {
PermissionCache.invalidateCache();
}
}
Aggregations