Search in sources :

Example 1 with LdapDynamicGroup

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;
}
Also used : Account(com.zimbra.cs.account.Account) LdapDynamicGroup(com.zimbra.cs.account.ldap.entry.LdapDynamicGroup) Group(com.zimbra.cs.account.Group) HashMap(java.util.HashMap) Element(com.zimbra.common.soap.Element) Provisioning(com.zimbra.cs.account.Provisioning) Entry(com.zimbra.cs.account.Entry) MemberOfSelector(com.zimbra.soap.account.type.MemberOfSelector) ZimbraSoapContext(com.zimbra.soap.ZimbraSoapContext)

Example 2 with LdapDynamicGroup

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;
}
Also used : Account(com.zimbra.cs.account.Account) LdapDynamicGroup(com.zimbra.cs.account.ldap.entry.LdapDynamicGroup) Group(com.zimbra.cs.account.Group) ZimbraSoapContext(com.zimbra.soap.ZimbraSoapContext) Element(com.zimbra.common.soap.Element) Provisioning(com.zimbra.cs.account.Provisioning)

Example 3 with LdapDynamicGroup

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);
}
Also used : Account(com.zimbra.cs.account.Account) GuestAccount(com.zimbra.cs.account.GuestAccount) LdapAccount(com.zimbra.cs.account.ldap.entry.LdapAccount) ZLdapContext(com.zimbra.cs.ldap.ZLdapContext) HashMap(java.util.HashMap) LdapDynamicGroup(com.zimbra.cs.account.ldap.entry.LdapDynamicGroup) ArrayList(java.util.ArrayList)

Example 4 with LdapDynamicGroup

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);
}
Also used : Account(com.zimbra.cs.account.Account) GuestAccount(com.zimbra.cs.account.GuestAccount) LdapAccount(com.zimbra.cs.account.ldap.entry.LdapAccount) ZLdapContext(com.zimbra.cs.ldap.ZLdapContext) HashMap(java.util.HashMap) LdapDynamicGroup(com.zimbra.cs.account.ldap.entry.LdapDynamicGroup) ArrayList(java.util.ArrayList) AccountServiceException(com.zimbra.cs.account.AccountServiceException) AuthFailedServiceException(com.zimbra.cs.account.AccountServiceException.AuthFailedServiceException) ServiceException(com.zimbra.common.service.ServiceException) HashSet(java.util.HashSet)

Example 5 with LdapDynamicGroup

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();
    }
}
Also used : ZMutableEntry(com.zimbra.cs.ldap.ZMutableEntry) LdapEntryAlreadyExistException(com.zimbra.cs.ldap.LdapException.LdapEntryAlreadyExistException) ZLdapContext(com.zimbra.cs.ldap.ZLdapContext) HashMap(java.util.HashMap) LdapDynamicGroup(com.zimbra.cs.account.ldap.entry.LdapDynamicGroup) AccountServiceException(com.zimbra.cs.account.AccountServiceException) AccountServiceException(com.zimbra.cs.account.AccountServiceException) AuthFailedServiceException(com.zimbra.cs.account.AccountServiceException.AuthFailedServiceException) ServiceException(com.zimbra.common.service.ServiceException) LdapDomain(com.zimbra.cs.account.ldap.entry.LdapDomain) Domain(com.zimbra.cs.account.Domain) LdapException(com.zimbra.cs.ldap.LdapException)

Aggregations

LdapDynamicGroup (com.zimbra.cs.account.ldap.entry.LdapDynamicGroup)10 ZLdapContext (com.zimbra.cs.ldap.ZLdapContext)6 Account (com.zimbra.cs.account.Account)5 ServiceException (com.zimbra.common.service.ServiceException)4 AccountServiceException (com.zimbra.cs.account.AccountServiceException)4 AuthFailedServiceException (com.zimbra.cs.account.AccountServiceException.AuthFailedServiceException)4 HashMap (java.util.HashMap)4 Group (com.zimbra.cs.account.Group)3 GuestAccount (com.zimbra.cs.account.GuestAccount)3 LdapAccount (com.zimbra.cs.account.ldap.entry.LdapAccount)3 Element (com.zimbra.common.soap.Element)2 DynamicGroup (com.zimbra.cs.account.DynamicGroup)2 Provisioning (com.zimbra.cs.account.Provisioning)2 ZimbraSoapContext (com.zimbra.soap.ZimbraSoapContext)2 ArrayList (java.util.ArrayList)2 HashSet (java.util.HashSet)2 Domain (com.zimbra.cs.account.Domain)1 Entry (com.zimbra.cs.account.Entry)1 LdapDistributionList (com.zimbra.cs.account.ldap.entry.LdapDistributionList)1 LdapDomain (com.zimbra.cs.account.ldap.entry.LdapDomain)1