Search in sources :

Example 1 with DynamicGroup

use of com.zimbra.cs.account.DynamicGroup in project zm-mailbox by Zimbra.

the class CollectAllEffectiveRights method collect.

private void collect() throws ServiceException {
    if (mRightBearer instanceof GlobalAdmin) {
        for (TargetType tt : TargetType.values()) {
            EffectiveRights er = new EffectiveRights(tt.getCode(), null, null, mRightBearer.getId(), mRightBearer.getName());
            Entry target;
            if (TargetType.config == tt) {
                target = mProv.getConfig();
            } else if (TargetType.global == tt) {
                target = mProv.getGlobalGrant();
            } else {
                target = PseudoTarget.createPseudoTarget(mProv, tt, null, null, true, null, null, null);
            }
            CollectEffectiveRights.getEffectiveRights(mRightBearer, target, tt, mExpandSetAttrs, mExpandGetAttrs, er);
            mResult.setAll(tt, er);
        }
        return;
    }
    // we want all target types
    Set<TargetType> targetTypesToSearch = new HashSet<TargetType>(Arrays.asList(TargetType.values()));
    // get the set of zimbraId of the grantees to search for
    Set<String> granteeIdsToSearch = mGrantee.getIdAndGroupIds();
    // add external group grants that *may* apply
    if (mGrantee.isAccount()) {
        Domain domain = mProv.getDomain(mGrantee.getAccount());
        granteeIdsToSearch.add(ZimbraACE.ExternalGroupInfo.encode(domain.getId(), ""));
    }
    SearchGrants searchGrants = new SearchGrants(mProv, targetTypesToSearch, granteeIdsToSearch);
    Set<GrantsOnTarget> grantsOnTargets = searchGrants.doSearch().getResults(true);
    // staging for group grants
    Set<Group> groupsWithGrants = new HashSet<Group>();
    //
    for (GrantsOnTarget grantsOnTarget : grantsOnTargets) {
        Entry grantedOnEntry = grantsOnTarget.getTargetEntry();
        ZimbraACL acl = grantsOnTarget.getAcl();
        TargetType targetType = TargetType.getTargetType(grantedOnEntry);
        if (targetType == TargetType.global) {
            computeRightsInheritedFromGlobalGrant();
        } else if (targetType == TargetType.domain) {
            computeRightsInheritedFromDomain((Domain) grantedOnEntry);
            computeSubDomainRightsInheritedFromDomain(acl, (Domain) grantedOnEntry);
        } else if (targetType == TargetType.dl) {
            groupsWithGrants.add((DistributionList) grantedOnEntry);
        } else if (targetType == TargetType.group) {
            groupsWithGrants.add((DynamicGroup) grantedOnEntry);
        }
    }
    //
    // Stage 2
    //
    // process group grants
    //
    // first, shape all members in all groups with grants into "shapes"
    //
    // e.g. if the grant search returned three groups: A, B, C
    //      group A contains members m1, m2, m3
    //      group B contains members m2, m3, m4
    //      group C contains members m5
    //
    //      (assuming all m{X} are accounts)
    //
    //      After "shaping", the accountShapes Set will contain 4 shapes:
    //      shape A  - m1
    //      shape AB - m2, m3
    //      shape B  - m4
    //      shape C  - m5
    //
    /*
         * because of bug 68820, we have to also take into accounts all sub groups
         * of groupsWithGrants when we build shapes - even if the sub groups don't
         * have any grants.
         *
         * Prior to bug 68820, we didn't have to do this(i.e. add in sub groups
         * that don't have any grants when shapes are computed), because sub groups
         * dont't have grants would never affect how grants are inherited - all grants
         * get inherited to sub groups and their member accounts/crs.
         *
         * But bug 68820 introduced a new right modifier - DISINHERIT_SUB_GROUPS,
         * that controls whether a grant on a group can be inherited by sub groups and
         * their account/cr members.
         *
         * Now the input groups for calculating shapes are:
         * union of (groups have grants and all their sub groups)
         *
         * This will result in more shares than before if non ofthe sub groups has grants,
         * but if spawned shapes actually have the same effective rights, they will be
         * merged by RightsByTargetType.addAggregation(), in that it checks if ther are
         * already an aggregation with the exact the same right.  If there are, then just
         * add the targets to the existing aggregation, instead of adding new ones.
         */
    Set<String> processedGroups = new HashSet<String>();
    Set<GroupShape> accountShapes = new HashSet<GroupShape>();
    Set<GroupShape> calendarResourceShapes = new HashSet<GroupShape>();
    Set<GroupShape> distributionListShapes = new HashSet<GroupShape>();
    for (Group group : groupsWithGrants) {
        String groupName = group.getName().toLowerCase();
        if (processedGroups.contains(groupName)) {
            continue;
        } else {
            processedGroups.add(groupName);
        }
        AllGroupMembers allMembers = getAllGroupMembers(group);
        GroupShape.shapeMembers(TargetType.account, accountShapes, allMembers);
        GroupShape.shapeMembers(TargetType.calresource, calendarResourceShapes, allMembers);
        GroupShape.shapeMembers(TargetType.dl, distributionListShapes, allMembers);
        // no need to get TargetType.group members of the group, because
        // dynamic group cannot be a member of a Distribution list or another
        // dynamic group
        processedGroups.add(group.getId());
        /*
             * handle sub groups.  allMembers already contains a flat set of all members
             * of group that is a DistributionList, just go through the flat set and compute
             * shares for each.  If group is a dynamic group, we should never get into
             * the following loop, because there should be no nested groups member of
             * dynamic group.
             */
        for (String nestedGoupMember : allMembers.getMembers(TargetType.dl)) {
            String nestedGoupMemberName = nestedGoupMember.toLowerCase();
            if (processedGroups.contains(nestedGoupMemberName)) {
                continue;
            } else {
                processedGroups.add(nestedGoupMemberName);
            }
            DistributionList subDl = mProv.get(DistributionListBy.name, nestedGoupMemberName);
            // sanity check, shout not be null
            if (subDl != null) {
                AllGroupMembers allMembersOfSubDl = getAllGroupMembers(subDl);
                GroupShape.shapeMembers(TargetType.account, accountShapes, allMembersOfSubDl);
                GroupShape.shapeMembers(TargetType.calresource, calendarResourceShapes, allMembersOfSubDl);
                GroupShape.shapeMembers(TargetType.dl, distributionListShapes, allMembersOfSubDl);
            }
        }
    }
    if (ZimbraLog.acl.isDebugEnabled()) {
        GroupShape.debug("accountShapes", accountShapes);
        GroupShape.debug("calendarResourceShapes", calendarResourceShapes);
        GroupShape.debug("distributionListShapes", distributionListShapes);
    }
    // then, for each group shape, generate a RightAggregation and record in the AllEffectiveRights.
    // if any of the entries in a shape also have grants as an individual, the effective rigths for
    // those entries will be replaced in stage 3.
    Set<String> entryIdsHasGrants = new HashSet<String>();
    for (GrantsOnTarget grantsOnTarget : grantsOnTargets) {
        Entry grantedOnEntry = grantsOnTarget.getTargetEntry();
        if (grantedOnEntry instanceof NamedEntry) {
            entryIdsHasGrants.add(((NamedEntry) grantedOnEntry).getId());
        }
    }
    computeRightsOnGroupShape(TargetType.account, accountShapes, entryIdsHasGrants);
    computeRightsOnGroupShape(TargetType.calresource, calendarResourceShapes, entryIdsHasGrants);
    computeRightsOnGroupShape(TargetType.dl, distributionListShapes, entryIdsHasGrants);
    //
    for (GrantsOnTarget grantsOnTarget : grantsOnTargets) {
        Entry grantedOnEntry = grantsOnTarget.getTargetEntry();
        ZimbraACL acl = grantsOnTarget.getAcl();
        TargetType targetType = TargetType.getTargetType(grantedOnEntry);
        if (targetType != TargetType.global) {
            computeRightsOnEntry(targetType, grantedOnEntry);
        }
    }
}
Also used : DynamicGroup(com.zimbra.cs.account.DynamicGroup) Group(com.zimbra.cs.account.Group) DynamicGroup(com.zimbra.cs.account.DynamicGroup) EffectiveRights(com.zimbra.cs.account.accesscontrol.RightCommand.EffectiveRights) AllEffectiveRights(com.zimbra.cs.account.accesscontrol.RightCommand.AllEffectiveRights) GrantsOnTarget(com.zimbra.cs.account.accesscontrol.SearchGrants.GrantsOnTarget) NamedEntry(com.zimbra.cs.account.NamedEntry) NamedEntry(com.zimbra.cs.account.NamedEntry) Entry(com.zimbra.cs.account.Entry) Domain(com.zimbra.cs.account.Domain) GlobalAdmin(com.zimbra.cs.account.accesscontrol.RightBearer.GlobalAdmin) HashSet(java.util.HashSet) DistributionList(com.zimbra.cs.account.DistributionList)

Example 2 with DynamicGroup

use of com.zimbra.cs.account.DynamicGroup in project zm-mailbox by Zimbra.

the class LdapProvisioning method getDLBasic.

private DistributionList getDLBasic(Key.DistributionListBy keyType, String key, ZLdapContext zlc) throws ServiceException {
    Group group = getGroupFromCache(keyType, key);
    if (group instanceof DistributionList) {
        return (DistributionList) group;
    } else if (group instanceof DynamicGroup) {
        return null;
    }
    // not in cache, fetch from LDAP
    DistributionList dl = null;
    switch(keyType) {
        case id:
            dl = getDistributionListByQuery(mDIT.mailBranchBaseDN(), filterFactory.distributionListById(key), zlc, true);
            break;
        case name:
            dl = getDistributionListByQuery(mDIT.mailBranchBaseDN(), filterFactory.distributionListByName(key), zlc, true);
            break;
        default:
            return null;
    }
    if (dl != null) {
        putInGroupCache(dl);
    }
    return dl;
}
Also used : Group(com.zimbra.cs.account.Group) DynamicGroup(com.zimbra.cs.account.DynamicGroup) LdapDynamicGroup(com.zimbra.cs.account.ldap.entry.LdapDynamicGroup) DynamicGroup(com.zimbra.cs.account.DynamicGroup) LdapDynamicGroup(com.zimbra.cs.account.ldap.entry.LdapDynamicGroup) LdapDistributionList(com.zimbra.cs.account.ldap.entry.LdapDistributionList) DistributionList(com.zimbra.cs.account.DistributionList)

Example 3 with DynamicGroup

use of com.zimbra.cs.account.DynamicGroup in project zm-mailbox by Zimbra.

the class LdapProvisioning method getContainingDynamicGroups.

/**
     * Get Dynamic Groups this account is a member of due to the value of the "zimbraMemberOf" attribute.
     * i.e. excludes groups this account is a member of because it satisfies the LDAP filter specified in the
     *      group's MemberURL where that MemberURL is a custom one.
     * @param acct
     * @return
     * @throws ServiceException
     */
private List<DynamicGroup> getContainingDynamicGroups(Account acct) throws ServiceException {
    List<DynamicGroup> groups = new ArrayList<DynamicGroup>();
    Set<String> memberOf = getAllContainingDynamicGroupIDs(acct);
    for (String groupId : memberOf) {
        DynamicGroup dynGroup = getDynamicGroupBasic(Key.DistributionListBy.id, groupId, null);
        if (dynGroup != null && !dynGroup.isMembershipDefinedByCustomURL()) {
            groups.add(dynGroup);
        }
    }
    return groups;
}
Also used : DynamicGroup(com.zimbra.cs.account.DynamicGroup) LdapDynamicGroup(com.zimbra.cs.account.ldap.entry.LdapDynamicGroup) ArrayList(java.util.ArrayList)

Example 4 with DynamicGroup

use of com.zimbra.cs.account.DynamicGroup in project zm-mailbox by Zimbra.

the class LdapProvisioning method createDynamicGroup.

private DynamicGroup createDynamicGroup(String groupAddress, Map<String, Object> groupAttrs, Account creator) throws ServiceException {
    SpecialAttrs specialAttrs = mDIT.handleSpecialAttrs(groupAttrs);
    String baseDn = specialAttrs.getLdapBaseDn();
    groupAddress = groupAddress.toLowerCase().trim();
    EmailAddress addr = new EmailAddress(groupAddress);
    String localPart = addr.getLocalPart();
    String domainName = addr.getDomain();
    domainName = IDNUtil.toAsciiDomainName(domainName);
    groupAddress = EmailAddress.getAddress(localPart, domainName);
    validEmailAddress(groupAddress);
    CallbackContext callbackContext = new CallbackContext(CallbackContext.Op.CREATE);
    callbackContext.setCreatingEntryName(groupAddress);
    // remove zimbraIsACLGroup from attrs if provided, to avoid the immutable check
    Object providedZimbraIsACLGroup = groupAttrs.get(A_zimbraIsACLGroup);
    if (providedZimbraIsACLGroup != null) {
        groupAttrs.remove(A_zimbraIsACLGroup);
    }
    AttributeManager.getInstance().preModify(groupAttrs, null, callbackContext, true);
    // put zimbraIsACLGroup back
    if (providedZimbraIsACLGroup != null) {
        groupAttrs.put(A_zimbraIsACLGroup, providedZimbraIsACLGroup);
    }
    ZLdapContext zlc = null;
    try {
        zlc = LdapClient.getContext(LdapServerType.MASTER, LdapUsage.CREATE_DYNAMICGROUP);
        Domain domain = getDomainByAsciiName(domainName, zlc);
        if (domain == null) {
            throw AccountServiceException.NO_SUCH_DOMAIN(domainName);
        }
        if (!domain.isLocal()) {
            throw ServiceException.INVALID_REQUEST("domain type must be local", null);
        }
        String domainDN = ((LdapDomain) domain).getDN();
        /*
             * ====================================
             * create the main dynamic group entry
             * ====================================
             */
        ZMutableEntry entry = LdapClient.createMutableEntry();
        entry.mapToAttrs(groupAttrs);
        Set<String> ocs = LdapObjectClass.getGroupObjectClasses(this);
        entry.addAttr(A_objectClass, ocs);
        String zimbraId = LdapUtil.generateUUID();
        // create a UUID for the static unit entry
        String staticUnitZimbraId = LdapUtil.generateUUID();
        String createTimestamp = LdapDateUtil.toGeneralizedTime(new Date());
        entry.setAttr(A_zimbraId, zimbraId);
        entry.setAttr(A_zimbraCreateTimestamp, createTimestamp);
        entry.setAttr(A_mail, groupAddress);
        entry.setAttr(A_dgIdentity, LC.zimbra_ldap_userdn.value());
        // unlike accounts (which have a zimbraMailDeliveryAddress for the primary,
        // and zimbraMailAliases only for aliases), DLs use zimbraMailAlias for both.
        // Postfix uses these two attributes to route mail, and zimbraMailDeliveryAddress
        // indicates that something has a physical mailbox, which DLs don't.
        entry.setAttr(A_zimbraMailAlias, groupAddress);
        /*
            // allow only users in the same domain
            String memberURL = String.format("ldap:///%s??one?(zimbraMemberOf=%s)",
                    mDIT.domainDNToAccountBaseDN(domainDN), groupAddress);
            */
        String specifiedIsACLGroup = entry.getAttrString(A_zimbraIsACLGroup);
        boolean isACLGroup;
        if (!entry.hasAttribute(A_memberURL)) {
            String memberURL = LdapDynamicGroup.getDefaultMemberURL(zimbraId, staticUnitZimbraId);
            entry.setAttr(Provisioning.A_memberURL, memberURL);
            // or specified to be TRUE;
            if (specifiedIsACLGroup == null) {
                entry.setAttr(A_zimbraIsACLGroup, ProvisioningConstants.TRUE);
            } else if (ProvisioningConstants.FALSE.equals(specifiedIsACLGroup)) {
                throw ServiceException.INVALID_REQUEST("No custom " + A_memberURL + " is provided, " + A_zimbraIsACLGroup + " cannot be set to FALSE", null);
            }
            isACLGroup = true;
        } else {
            // We want to be able to use dynamic groups as ACLs, for instance when sharing a folder with a group
            // This used to be disallowed via a requirement that zimbraIsACLGroup be specified and set to FALSE.
            // That requirement has been dropped.
            isACLGroup = !ProvisioningConstants.FALSE.equals(specifiedIsACLGroup);
        }
        // by default a dynamic group is always created enabled
        if (!entry.hasAttribute(Provisioning.A_zimbraMailStatus)) {
            entry.setAttr(A_zimbraMailStatus, MAIL_STATUS_ENABLED);
        }
        String mailStatus = entry.getAttrString(A_zimbraMailStatus);
        entry.setAttr(A_cn, localPart);
        // entry.setAttr(A_uid, localPart); need to use uid if we move dynamic groups to the ou=people tree
        setGroupHomeServer(entry, creator);
        String dn = mDIT.dynamicGroupNameLocalPartToDN(localPart, domainDN);
        entry.setDN(dn);
        zlc.createEntry(entry);
        if (isACLGroup) {
            /*
                 * ===========================================================
                 * create the dynamic group unit entry, for internal addresses
                 * ===========================================================
                 */
            String dynamicUnitLocalpart = dynamicGroupDynamicUnitLocalpart(localPart);
            String dynamicUnitAddr = EmailAddress.getAddress(dynamicUnitLocalpart, domainName);
            entry = LdapClient.createMutableEntry();
            ocs = LdapObjectClass.getGroupDynamicUnitObjectClasses(this);
            entry.addAttr(A_objectClass, ocs);
            String dynamicUnitZimbraId = LdapUtil.generateUUID();
            entry.setAttr(A_cn, DYNAMIC_GROUP_DYNAMIC_UNIT_NAME);
            entry.setAttr(A_zimbraId, dynamicUnitZimbraId);
            // id of the main group
            entry.setAttr(A_zimbraGroupId, zimbraId);
            entry.setAttr(A_zimbraCreateTimestamp, createTimestamp);
            entry.setAttr(A_mail, dynamicUnitAddr);
            entry.setAttr(A_zimbraMailAlias, dynamicUnitAddr);
            entry.setAttr(A_zimbraMailStatus, mailStatus);
            entry.setAttr(A_dgIdentity, LC.zimbra_ldap_userdn.value());
            // id of the main group
            String memberURL = LdapDynamicGroup.getDefaultDynamicUnitMemberURL(zimbraId);
            entry.setAttr(Provisioning.A_memberURL, memberURL);
            String dynamicUnitDN = mDIT.dynamicGroupUnitNameToDN(DYNAMIC_GROUP_DYNAMIC_UNIT_NAME, dn);
            entry.setDN(dynamicUnitDN);
            zlc.createEntry(entry);
            /*
                 * ==========================================================
                 * create the static group unit entry, for external addresses
                 * ==========================================================
                 */
            entry = LdapClient.createMutableEntry();
            ocs = LdapObjectClass.getGroupStaticUnitObjectClasses(this);
            entry.addAttr(A_objectClass, ocs);
            entry.setAttr(A_cn, DYNAMIC_GROUP_STATIC_UNIT_NAME);
            entry.setAttr(A_zimbraId, staticUnitZimbraId);
            // id of the main group
            entry.setAttr(A_zimbraGroupId, zimbraId);
            entry.setAttr(A_zimbraCreateTimestamp, createTimestamp);
            String staticUnitDN = mDIT.dynamicGroupUnitNameToDN(DYNAMIC_GROUP_STATIC_UNIT_NAME, dn);
            entry.setDN(staticUnitDN);
            zlc.createEntry(entry);
        }
        /*
             * all is well, get the group by id
             */
        DynamicGroup group = getDynamicGroupBasic(DistributionListBy.id, zimbraId, zlc);
        if (group != null) {
            AttributeManager.getInstance().postModify(groupAttrs, group, callbackContext);
            removeExternalAddrsFromAllDynamicGroups(group.getAllAddrsSet(), zlc);
            allDLs.addGroup(group);
        } else {
            throw ServiceException.FAILURE("unable to get dynamic group after creating LDAP entry: " + groupAddress, null);
        }
        return group;
    } catch (LdapEntryAlreadyExistException nabe) {
        throw AccountServiceException.DISTRIBUTION_LIST_EXISTS(groupAddress);
    } catch (LdapException e) {
        throw e;
    } catch (AccountServiceException e) {
        throw e;
    } finally {
        LdapClient.closeContext(zlc);
    }
}
Also used : ZMutableEntry(com.zimbra.cs.ldap.ZMutableEntry) DynamicGroup(com.zimbra.cs.account.DynamicGroup) LdapDynamicGroup(com.zimbra.cs.account.ldap.entry.LdapDynamicGroup) LdapEntryAlreadyExistException(com.zimbra.cs.ldap.LdapException.LdapEntryAlreadyExistException) ZLdapContext(com.zimbra.cs.ldap.ZLdapContext) LdapDomain(com.zimbra.cs.account.ldap.entry.LdapDomain) EmailAddress(com.zimbra.cs.account.names.NameUtil.EmailAddress) Date(java.util.Date) AccountServiceException(com.zimbra.cs.account.AccountServiceException) CallbackContext(com.zimbra.cs.account.callback.CallbackContext) LdapDomain(com.zimbra.cs.account.ldap.entry.LdapDomain) Domain(com.zimbra.cs.account.Domain) LdapException(com.zimbra.cs.ldap.LdapException)

Example 5 with DynamicGroup

use of com.zimbra.cs.account.DynamicGroup in project zm-mailbox by Zimbra.

the class SmtpRecipientValidator method validate.

@Override
public Iterable<String> validate(String recipient) {
    try {
        Provisioning prov = Provisioning.getInstance();
        Account account = prov.get(AccountBy.name, recipient);
        if (account != null) {
            return Arrays.asList(account.getName());
        } else {
            Group group = prov.getGroup(Key.DistributionListBy.name, recipient);
            if (group != null) {
                String[] members;
                if (group instanceof DynamicGroup) {
                    members = ((DynamicGroup) group).getAllMembers(true);
                } else {
                    members = group.getAllMembers();
                }
                return Arrays.asList(members);
            }
        }
    } catch (ServiceException e) {
        log.error("Unable to validate recipient %s", recipient, e);
    }
    return Collections.emptyList();
}
Also used : Account(com.zimbra.cs.account.Account) DynamicGroup(com.zimbra.cs.account.DynamicGroup) Group(com.zimbra.cs.account.Group) DynamicGroup(com.zimbra.cs.account.DynamicGroup) ServiceException(com.zimbra.common.service.ServiceException) Provisioning(com.zimbra.cs.account.Provisioning)

Aggregations

DynamicGroup (com.zimbra.cs.account.DynamicGroup)24 LdapDynamicGroup (com.zimbra.cs.account.ldap.entry.LdapDynamicGroup)10 ServiceException (com.zimbra.common.service.ServiceException)9 Account (com.zimbra.cs.account.Account)9 DistributionList (com.zimbra.cs.account.DistributionList)9 Group (com.zimbra.cs.account.Group)7 Test (org.junit.Test)7 Domain (com.zimbra.cs.account.Domain)6 NamedEntry (com.zimbra.cs.account.NamedEntry)6 LdapDomain (com.zimbra.cs.account.ldap.entry.LdapDomain)5 HashMap (java.util.HashMap)5 Entry (com.zimbra.cs.account.Entry)4 GuestAccount (com.zimbra.cs.account.GuestAccount)3 SearchDirectoryOptions (com.zimbra.cs.account.SearchDirectoryOptions)3 ProvTest (com.zimbra.qa.unittest.prov.ProvTest)3 Element (com.zimbra.common.soap.Element)2 Provisioning (com.zimbra.cs.account.Provisioning)2 Names (com.zimbra.qa.unittest.prov.Names)2 ZimbraSoapContext (com.zimbra.soap.ZimbraSoapContext)2 HashSet (java.util.HashSet)2