use of com.zimbra.cs.account.ldap.entry.LdapDynamicGroup in project zm-mailbox by Zimbra.
the class GetAccountDistributionLists method handle.
@Override
public Element handle(Element request, Map<String, Object> context) throws ServiceException {
ZimbraSoapContext zsc = getZimbraSoapContext(context);
Account acct = getRequestedAccount(zsc);
Provisioning prov = Provisioning.getInstance();
if (!canAccessAccount(zsc, acct)) {
throw ServiceException.PERM_DENIED("can not access account");
}
boolean needOwnerOf = request.getAttributeBool(AccountConstants.A_OWNER_OF, false);
MemberOfSelector needMemberOf = MemberOfSelector.fromString(request.getAttribute(AccountConstants.A_MEMBER_OF, MemberOfSelector.directOnly.name()));
Iterable<String> needAttrs = Splitter.on(',').trimResults().split(request.getAttribute(AccountConstants.A_ATTRS, ""));
Set<Group> ownerOf = null;
List<Group> memberOf = null;
HashMap<String, String> via = new HashMap<String, String>();
if (needOwnerOf) {
ownerOf = Group.GroupOwner.getOwnedGroups(acct);
}
if (MemberOfSelector.none != needMemberOf) {
memberOf = prov.getGroups(acct, MemberOfSelector.directOnly == needMemberOf, via);
}
/*
* merge the two results into one locale-sensitive sorted list
*/
Set<Entry> combined = Sets.newHashSet();
Set<String> combinedIds = Sets.newHashSet();
Set<String> ownerOfGroupIds = Sets.newHashSet();
Set<String> memberOfGroupIds = Sets.newHashSet();
if (ownerOf != null) {
for (Group group : ownerOf) {
String groupId = group.getId();
ownerOfGroupIds.add(groupId);
if (!combinedIds.contains(groupId)) {
combined.add(group);
combinedIds.add(groupId);
}
}
}
if (memberOf != null) {
for (Group group : memberOf) {
String groupId = group.getId();
memberOfGroupIds.add(groupId);
if (!combinedIds.contains(groupId)) {
combined.add(group);
combinedIds.add(groupId);
}
}
}
// sort it
List<Entry> sortedGroups = Entry.sortByDisplayName(combined, acct.getLocale());
Element response = zsc.createElement(AccountConstants.GET_ACCOUNT_DISTRIBUTION_LISTS_RESPONSE);
for (Entry entry : sortedGroups) {
Group group = (Group) entry;
Element eDL = response.addElement(AccountConstants.E_DL);
eDL.addAttribute(AccountConstants.A_NAME, group.getName());
if (group.isDynamic()) {
eDL.addAttribute(AccountConstants.A_REF, ((LdapDynamicGroup) group).getDN());
} else {
eDL.addAttribute(AccountConstants.A_REF, ((LdapDistributionList) group).getDN());
}
eDL.addAttribute(AccountConstants.A_ID, group.getId());
eDL.addAttribute(AccountConstants.A_DISPLAY, group.getDisplayName());
eDL.addAttribute(AccountConstants.A_DYNAMIC, group.isDynamic());
boolean isOwner = ownerOfGroupIds.contains(group.getId());
if (needOwnerOf) {
eDL.addAttribute(AccountConstants.A_IS_OWNER, isOwner);
}
if (MemberOfSelector.none != needMemberOf) {
boolean isMember = memberOfGroupIds.contains(group.getId());
eDL.addAttribute(AccountConstants.A_IS_MEMBER, isMember);
if (isMember) {
String viaDl = via.get(group.getName());
if (viaDl != null) {
eDL.addAttribute(AccountConstants.A_VIA, viaDl);
}
}
}
Set<String> returnAttrs = GetDistributionList.visibleAttrs(needAttrs, isOwner);
if (!returnAttrs.isEmpty()) {
GetDistributionList.encodeAttrs(group, eDL, returnAttrs);
}
}
return response;
}
use of com.zimbra.cs.account.ldap.entry.LdapDynamicGroup in project zm-mailbox by Zimbra.
the class CreateDistributionList method handle.
public Element handle(Element request, Map<String, Object> context) throws ServiceException {
ZimbraSoapContext zsc = getZimbraSoapContext(context);
Provisioning prov = Provisioning.getInstance();
Account acct = getAuthenticatedAccount(zsc);
String name = request.getAttribute(AccountConstants.E_NAME).toLowerCase();
if (!AccessManager.getInstance().canCreateGroup(acct, name)) {
throw ServiceException.PERM_DENIED("you do not have sufficient rights to create distribution list");
}
Map<String, Object> attrs = AccountService.getKeyValuePairs(request, AccountConstants.E_A, AccountConstants.A_N);
boolean dynamic = request.getAttributeBool(AccountConstants.A_DYNAMIC, true);
// creator of the group will automatically become the first owner of the group
Account creator = getAuthenticatedAccount(zsc);
Group group = prov.createDelegatedGroup(name, attrs, dynamic, creator);
ZimbraLog.security.info(ZimbraLog.encodeAttrs(new String[] { "cmd", "CreateDistributionList", "name", name }, attrs));
Element response = zsc.createElement(AccountConstants.CREATE_DISTRIBUTION_LIST_RESPONSE);
Element eDL = response.addElement(AccountConstants.E_DL);
eDL.addAttribute(AccountConstants.A_NAME, group.getName());
if (group.isDynamic()) {
eDL.addAttribute(AccountConstants.A_REF, ((LdapDynamicGroup) group).getDN());
} else {
eDL.addAttribute(AccountConstants.A_REF, ((LdapDistributionList) group).getDN());
}
eDL.addAttribute(AccountConstants.A_ID, group.getId());
GetDistributionList.encodeAttrs(group, eDL, null);
return response;
}
use of com.zimbra.cs.account.ldap.entry.LdapDynamicGroup in project zm-mailbox by Zimbra.
the class LdapProvisioning method addDynamicGroupMembers.
private void addDynamicGroupMembers(LdapDynamicGroup group, String[] members) throws ServiceException {
if (group.isMembershipDefinedByCustomURL()) {
throw ServiceException.INVALID_REQUEST("cannot add members to dynamic group with custom memberURL", null);
}
String groupId = group.getId();
List<Account> accts = new ArrayList<Account>();
List<String> externalAddrs = new ArrayList<String>();
// check for errors, and put valid accts to the queue
for (String member : members) {
String memberName = member.toLowerCase();
memberName = IDNUtil.toAsciiEmail(memberName);
Account acct = get(AccountBy.name, memberName);
if (acct == null) {
// addr is not an account (could still be a group or group unit address
// on the system), will check by addressExists.
externalAddrs.add(memberName);
} else {
// is an account
Set<String> memberOf = acct.getMultiAttrSet(Provisioning.A_zimbraMemberOf);
if (!memberOf.contains(groupId)) {
accts.add(acct);
}
// else the addr is already in the group, just skip it, do not throw
}
}
ZLdapContext zlc = null;
try {
zlc = LdapClient.getContext(LdapServerType.MASTER, LdapUsage.ADD_GROUP_MEMBER);
// on the system
if (!externalAddrs.isEmpty()) {
if (addressExists(zlc, externalAddrs.toArray(new String[externalAddrs.size()]))) {
throw ServiceException.INVALID_REQUEST("address cannot be a group: " + Arrays.deepToString(externalAddrs.toArray()), null);
}
}
/*
* add internal members
*/
for (Account acct : accts) {
Map<String, Object> attrs = new HashMap<String, Object>();
attrs.put("+" + Provisioning.A_zimbraMemberOf, groupId);
modifyLdapAttrs(acct, zlc, attrs);
clearUpwardMembershipCache(acct);
}
/*
* add external members on the static unit
*/
LdapDynamicGroup.StaticUnit staticUnit = group.getStaticUnit();
Set<String> existingAddrs = staticUnit.getMembersSet();
List<String> addrsToAdd = Lists.newArrayList();
for (String addr : externalAddrs) {
if (!existingAddrs.contains(addr)) {
addrsToAdd.add(addr);
}
}
if (!addrsToAdd.isEmpty()) {
Map<String, String[]> attrs = new HashMap<String, String[]>();
attrs.put("+" + LdapDynamicGroup.StaticUnit.MEMBER_ATTR, addrsToAdd.toArray(new String[addrsToAdd.size()]));
modifyLdapAttrs(staticUnit, zlc, attrs);
}
} finally {
LdapClient.closeContext(zlc);
}
PermissionCache.invalidateCache();
cleanGroupMembersCache(group);
}
use of com.zimbra.cs.account.ldap.entry.LdapDynamicGroup in project zm-mailbox by Zimbra.
the class LdapProvisioning method removeDynamicGroupMembers.
private void removeDynamicGroupMembers(LdapDynamicGroup group, String[] members, boolean externalOnly) throws ServiceException {
if (group.isMembershipDefinedByCustomURL()) {
throw ServiceException.INVALID_REQUEST(String.format("cannot remove members from dynamic group '%s' with custom memberURL", group.getName()), null);
}
String groupId = group.getId();
List<Account> accts = new ArrayList<Account>();
List<String> externalAddrs = new ArrayList<String>();
HashSet<String> failed = new HashSet<String>();
// check for errors, and put valid accts to the queue
for (String member : members) {
String memberName = member.toLowerCase();
boolean isBadAddr = false;
try {
memberName = IDNUtil.toAsciiEmail(memberName);
} catch (ServiceException e) {
// if the addr is not a valid email address, maybe they want to
// remove a bogus addr that somehow got in, just let it through.
memberName = member;
isBadAddr = true;
}
// always add all addrs to "externalAddrs".
externalAddrs.add(memberName);
if (!externalOnly) {
Account acct = isBadAddr ? null : get(AccountBy.name, member);
if (acct != null) {
Set<String> memberOf = acct.getMultiAttrSet(Provisioning.A_zimbraMemberOf);
if (memberOf.contains(groupId)) {
accts.add(acct);
} else {
// else the addr is not in the group, throw exception
failed.add(memberName);
}
}
}
}
if (!failed.isEmpty()) {
StringBuilder sb = new StringBuilder();
Iterator<String> iter = failed.iterator();
while (true) {
sb.append(iter.next());
if (!iter.hasNext())
break;
sb.append(",");
}
throw AccountServiceException.NO_SUCH_MEMBER(group.getName(), sb.toString());
}
ZLdapContext zlc = null;
try {
zlc = LdapClient.getContext(LdapServerType.MASTER, LdapUsage.REMOVE_GROUP_MEMBER);
/*
* remove internal members
*/
for (Account acct : accts) {
Map<String, Object> attrs = new HashMap<String, Object>();
attrs.put("-" + Provisioning.A_zimbraMemberOf, groupId);
modifyLdapAttrs(acct, zlc, attrs);
clearUpwardMembershipCache(acct);
}
/*
* remove external members on the static unit
*/
LdapDynamicGroup.StaticUnit staticUnit = group.getStaticUnit();
Set<String> existingAddrs = staticUnit.getMembersSet();
List<String> addrsToRemove = Lists.newArrayList();
for (String addr : externalAddrs) {
if (existingAddrs.contains(addr)) {
addrsToRemove.add(addr);
}
}
if (!addrsToRemove.isEmpty()) {
Map<String, String[]> attrs = new HashMap<String, String[]>();
attrs.put("-" + LdapDynamicGroup.StaticUnit.MEMBER_ATTR, addrsToRemove.toArray(new String[addrsToRemove.size()]));
modifyLdapAttrs(staticUnit, zlc, attrs);
}
} finally {
LdapClient.closeContext(zlc);
}
PermissionCache.invalidateCache();
cleanGroupMembersCache(group);
}
use of com.zimbra.cs.account.ldap.entry.LdapDynamicGroup in project zm-mailbox by Zimbra.
the class LdapProvisioning method renameDynamicGroup.
private void renameDynamicGroup(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_DYNAMICGROUP);
LdapDynamicGroup group = (LdapDynamicGroup) getDynamicGroupById(zimbraId, zlc, false);
if (group == null) {
throw AccountServiceException.NO_SUCH_DISTRIBUTION_LIST(zimbraId);
}
// prune cache
groupCache.remove(group);
String oldEmail = group.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(group, 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(group, 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(group, Provisioning.A_zimbraPrefAllowAddressForDelegatedSender, oldEmail, newEmail);
if (replacedAllowAddrForDelegatedSender.newAddrs().length > 0) {
attrs.put(Provisioning.A_zimbraPrefAllowAddressForDelegatedSender, replacedAllowAddrForDelegatedSender.newAddrs());
}
// the naming rdn
String rdnAttrName = mDIT.dynamicGroupNamingRdnAttr();
attrs.put(rdnAttrName, newLocal);
// move over the distribution list entry
String oldDn = group.getDN();
String newDn = mDIT.dynamicGroupDNRename(oldDn, newLocal, domain.getName());
boolean dnChanged = (!oldDn.equals(newDn));
if (dnChanged) {
// cn 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_cn);
zlc.renameEntry(oldDn, newDn);
}
// re-get the entry after move
group = (LdapDynamicGroup) getDynamicGroupById(zimbraId, zlc, false);
// doesn't throw exceptions, just logs
if (domainChanged) {
String newUid = group.getAttr(rdnAttrName);
moveAliases(zlc, replacedAliases, newDomain, newUid, oldDn, newDn, oldDomain, newDomain);
}
// could fail. So catch service exception here and log error
try {
// modify attrs on the mail entry
modifyAttrsInternal(group, zlc, attrs);
if (group.isIsACLGroup()) {
// modify attrs on the units (which are only present when group is an ACL Group)
String dynamicUnitNewLocal = dynamicGroupDynamicUnitLocalpart(newLocal);
String dynamicUnitNewEmail = dynamicUnitNewLocal + "@" + newDomain;
String dynamicUnitDN = mDIT.dynamicGroupUnitNameToDN(DYNAMIC_GROUP_DYNAMIC_UNIT_NAME, newDn);
ZMutableEntry entry = LdapClient.createMutableEntry();
entry.setAttr(A_mail, dynamicUnitNewEmail);
entry.setAttr(A_zimbraMailAlias, dynamicUnitNewEmail);
zlc.replaceAttributes(dynamicUnitDN, entry.getAttributes());
}
} catch (ServiceException e) {
ZimbraLog.account.error("dynamic group renamed to " + newLocal + " but failed to move old name's LDAP attributes", e);
throw e;
}
removeExternalAddrsFromAllDynamicGroups(group.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 dynamic group: " + zimbraId, e);
} finally {
LdapClient.closeContext(zlc);
}
if (domainChanged) {
PermissionCache.invalidateCache();
}
}
Aggregations