001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     bstefanescu
011 */
012package org.nuxeo.ecm.automation.features;
013
014import java.util.HashSet;
015import java.util.Set;
016
017import org.apache.commons.lang.StringUtils;
018import org.nuxeo.ecm.core.api.DocumentModel;
019import org.nuxeo.ecm.core.api.NuxeoGroup;
020import org.nuxeo.ecm.core.api.NuxeoPrincipal;
021import org.nuxeo.ecm.core.api.security.ACE;
022import org.nuxeo.ecm.core.api.security.ACL;
023import org.nuxeo.ecm.core.api.security.ACP;
024import org.nuxeo.ecm.core.api.security.PermissionProvider;
025import org.nuxeo.ecm.core.api.security.SecurityConstants;
026import org.nuxeo.ecm.platform.usermanager.UserManager;
027
028/**
029 * Provides helper methods to find extract permissions/principals info from documents.
030 *
031 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
032 * @author Anahide Tchertchian
033 */
034public class PrincipalHelper {
035
036    protected UserManager userManager;
037
038    protected PermissionProvider permissionProvider;
039
040    public PrincipalHelper(UserManager userManager, PermissionProvider permissionProvider) {
041        this.userManager = userManager;
042        this.permissionProvider = permissionProvider;
043    }
044
045    @SuppressWarnings("unchecked")
046    public Set<String> getEmailsForPermission(DocumentModel input, String permission, boolean ignoreGroups)
047            {
048        return (Set<String>) collectObjectsMatchingPermission(input, permission, ignoreGroups, true,
049                new EmailCollector(userManager.getUserSchemaName(), userManager.getUserEmailField()));
050    }
051
052    /**
053     * Resolves the list of identifiers for users and groups who have the given permission on given document.
054     *
055     * @param input document model to resolve users and groups on.
056     * @param permission the permission to check
057     * @param ignoreGroups if true, will ignore groups in resolution of ids
058     * @param resolveGroups if true, will resolve user members, iterating in the hierarchy of groups
059     * @param prefixIds if true, will prefix identifiers with {@link NuxeoPrincipal#PREFIX} and
060     *            {@link NuxeoGroup#PREFIX}
061     */
062    @SuppressWarnings("unchecked")
063    public Set<String> getUserAndGroupIdsForPermission(DocumentModel input, String permission, boolean ignoreGroups,
064            boolean resolveGroups, boolean prefixIds) {
065        return (Set<String>) collectObjectsMatchingPermission(input, permission, ignoreGroups, resolveGroups,
066                new IdCollector(prefixIds));
067    }
068
069    @SuppressWarnings("unchecked")
070    public Set<NuxeoPrincipal> getPrincipalsForPermission(DocumentModel input, String permission, boolean ignoreGroups,
071            boolean resolveGroups) {
072        return (Set<NuxeoPrincipal>) collectObjectsMatchingPermission(input, permission, ignoreGroups, resolveGroups,
073                new PrincipalCollector());
074    }
075
076    public Set<String> getEmailsFromGroup(String groupId, boolean resolveGroups) {
077        EmailCollector collector = new EmailCollector(userManager.getUserSchemaName(), userManager.getUserEmailField());
078        collectObjectsFromGroup(groupId, resolveGroups, collector);
079        return collector.getResult();
080    }
081
082    public Set<NuxeoPrincipal> getPrincipalsFromGroup(String groupId, boolean resolveGroups) {
083        PrincipalCollector collector = new PrincipalCollector();
084        collectObjectsFromGroup(groupId, resolveGroups, collector);
085        return collector.getResult();
086    }
087
088    public Set<String> getUserNamesFromGroup(String groupId, boolean resolveGroups, boolean prefixIds)
089            {
090        IdCollector collector = new IdCollector(prefixIds);
091        collectObjectsFromGroup(groupId, resolveGroups, collector);
092        return collector.getResult();
093    }
094
095    public void collectObjectsFromGroup(String groupId, boolean resolveGroups, Collector<?> collector)
096            {
097        NuxeoGroup group = userManager.getGroup(groupId);
098        if (group == null) {
099            userManager.getPrincipal(groupId);
100        } else {
101            for (String u : group.getMemberUsers()) {
102                NuxeoPrincipal principal = userManager.getPrincipal(u);
103                if (principal != null) {
104                    collector.collect(principal);
105                }
106            }
107            if (resolveGroups) {
108                for (String g : group.getMemberGroups()) {
109                    collectObjectsFromGroup(g, resolveGroups, collector);
110                }
111            }
112        }
113    }
114
115    public HashSet<?> collectObjectsMatchingPermission(DocumentModel input, String permission, boolean ignoreGroups,
116            boolean resolveGroups, Collector<?> collector) {
117        String[] perms = getPermissionsToCheck(permission);
118        ACP acp = input.getACP();
119        for (ACL acl : acp.getACLs()) {
120            for (ACE ace : acl.getACEs()) {
121                if (ace.isGranted() && permissionMatch(perms, ace.getPermission())) {
122                    NuxeoGroup group = userManager.getGroup(ace.getUsername());
123                    if (group == null) {
124                        // this may be a user
125                        collector.collect(userManager.getPrincipal(ace.getUsername()));
126                    } else if (!ignoreGroups) {
127                        if (resolveGroups) {
128                            resolveGroups(group, collector);
129                        } else {
130                            collector.collect(group);
131                        }
132                    }
133                }
134            }
135        }
136        return collector.getResult();
137    }
138
139    public void resolveGroups(NuxeoGroup group, Collector<?> collector) {
140        if (group != null) {
141            for (String memberUser : group.getMemberUsers()) {
142                collector.collect(userManager.getPrincipal(memberUser));
143            }
144            for (String subGroup : group.getMemberGroups()) {
145                resolveGroups(userManager.getGroup(subGroup), collector);
146            }
147        }
148    }
149
150    public String[] getPermissionsToCheck(String permission) {
151        String[] groups = permissionProvider.getPermissionGroups(permission);
152        if (groups == null) {
153            return new String[] { permission, SecurityConstants.EVERYTHING };
154        } else {
155            String[] perms = new String[groups.length + 2];
156            perms[0] = permission;
157            System.arraycopy(groups, 0, perms, 1, groups.length);
158            perms[groups.length + 1] = SecurityConstants.EVERYTHING;
159            return perms;
160        }
161    }
162
163    public boolean permissionMatch(String[] perms, String perm) {
164        for (String p : perms) {
165            if (p.equals(perm)) {
166                return true;
167            }
168        }
169        return false;
170    }
171
172    interface Collector<T> {
173
174        void collect(NuxeoPrincipal principal);
175
176        void collect(NuxeoGroup group);
177
178        HashSet<T> getResult();
179    }
180
181    public static class EmailCollector implements Collector<String> {
182
183        protected final String userSchemaName;
184
185        protected final String userEmailFieldName;
186
187        protected HashSet<String> result = new HashSet<String>();
188
189        EmailCollector(String userSchemaName, String userEmailFieldName) {
190            this.userSchemaName = userSchemaName;
191            this.userEmailFieldName = userEmailFieldName;
192        }
193
194        @Override
195        public void collect(NuxeoPrincipal principal) {
196            if (principal == null) {
197                return;
198            }
199            DocumentModel userEntry = principal.getModel();
200            String email = (String) userEntry.getProperty(userSchemaName, userEmailFieldName);
201            if (!StringUtils.isEmpty(email)) {
202                result.add(email);
203            }
204        }
205
206        @Override
207        public void collect(NuxeoGroup group) {
208            // do nothing
209        }
210
211        @Override
212        public HashSet<String> getResult() {
213            return result;
214        }
215    }
216
217    static class PrincipalCollector implements Collector<NuxeoPrincipal> {
218
219        protected HashSet<NuxeoPrincipal> result = new HashSet<NuxeoPrincipal>();
220
221        @Override
222        public void collect(NuxeoPrincipal principal) {
223            if (principal == null) {
224                return;
225            }
226            result.add(principal);
227        }
228
229        @Override
230        public void collect(NuxeoGroup group) {
231            // do nothing
232        }
233
234        @Override
235        public HashSet<NuxeoPrincipal> getResult() {
236            return result;
237        }
238    }
239
240    static class IdCollector implements Collector<String> {
241
242        protected final boolean prefixIds;
243
244        protected HashSet<String> result = new HashSet<String>();
245
246        IdCollector(boolean prefixIds) {
247            this.prefixIds = prefixIds;
248        }
249
250        @Override
251        public void collect(NuxeoPrincipal principal) {
252            if (principal != null) {
253                String name = principal.getName();
254                if (name != null) {
255                    if (prefixIds) {
256                        result.add(NuxeoPrincipal.PREFIX + name);
257                    } else {
258                        result.add(name);
259                    }
260                }
261            }
262        }
263
264        @Override
265        public void collect(NuxeoGroup group) {
266            if (group != null) {
267                String name = group.getName();
268                if (name != null) {
269                    if (prefixIds) {
270                        result.add(NuxeoGroup.PREFIX + name);
271                    } else {
272                        result.add(name);
273                    }
274                }
275            }
276        }
277
278        @Override
279        public HashSet<String> getResult() {
280            return result;
281        }
282
283    }
284
285}