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