1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package com.xpn.xwiki.user.impl.xwiki

File XWikiRightServiceImpl.java

 

Coverage histogram

../../../../../../img/srcFileCovDistChart8.png
54% of files have more coverage

Code metrics

196
434
19
1
1,011
746
166
0.38
22.84
19
8.74

Classes

Class Line # Actions
XWikiRightServiceImpl 61 434 0% 166 158
0.756548575.7%
 

Contributing tests

This file is covered by 25 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package com.xpn.xwiki.user.impl.xwiki;
21   
22    import java.util.ArrayList;
23    import java.util.Arrays;
24    import java.util.Collection;
25    import java.util.Collections;
26    import java.util.HashMap;
27    import java.util.HashSet;
28    import java.util.List;
29    import java.util.Map;
30   
31    import org.apache.commons.lang3.ArrayUtils;
32    import org.apache.commons.lang3.ObjectUtils;
33    import org.apache.commons.lang3.StringUtils;
34    import org.slf4j.Logger;
35    import org.slf4j.LoggerFactory;
36    import org.xwiki.model.EntityType;
37    import org.xwiki.model.reference.DocumentReference;
38    import org.xwiki.model.reference.DocumentReferenceResolver;
39    import org.xwiki.model.reference.EntityReference;
40    import org.xwiki.model.reference.EntityReferenceSerializer;
41   
42    import com.xpn.xwiki.XWikiContext;
43    import com.xpn.xwiki.XWikiException;
44    import com.xpn.xwiki.doc.XWikiDocument;
45    import com.xpn.xwiki.objects.BaseObject;
46    import com.xpn.xwiki.objects.classes.GroupsClass;
47    import com.xpn.xwiki.user.api.XWikiGroupService;
48    import com.xpn.xwiki.user.api.XWikiRightNotFoundException;
49    import com.xpn.xwiki.user.api.XWikiRightService;
50    import com.xpn.xwiki.user.api.XWikiUser;
51    import com.xpn.xwiki.util.Util;
52    import com.xpn.xwiki.web.Utils;
53   
54    /**
55    * Default implementation of {@link XWikiRightService}.
56    *
57    * @version $Id: 40845af33585a3128f6ca435dad3cf9e7e0df961 $
58    * @deprecated since 4.0, use XWikiCachingRightService instead
59    */
60    @Deprecated
 
61    public class XWikiRightServiceImpl implements XWikiRightService
62    {
63    public static final EntityReference RIGHTCLASS_REFERENCE = new EntityReference("XWikiRights", EntityType.DOCUMENT,
64    new EntityReference("XWiki", EntityType.SPACE));
65   
66    public static final EntityReference GLOBALRIGHTCLASS_REFERENCE = new EntityReference("XWikiGlobalRights",
67    EntityType.DOCUMENT, new EntityReference("XWiki", EntityType.SPACE));
68   
69    private static final Logger LOGGER = LoggerFactory.getLogger(XWikiRightServiceImpl.class);
70   
71    private static final EntityReference XWIKIPREFERENCES_REFERENCE = new EntityReference("XWikiPreferences",
72    EntityType.DOCUMENT, new EntityReference("XWiki", EntityType.SPACE));
73   
74    private static final List<String> ALLLEVELS = Arrays.asList("admin", "view", "edit", "comment", "delete",
75    "undelete", "register", "programming");
76   
77    private static final EntityReference DEFAULTUSERSPACE = new EntityReference("XWiki", EntityType.SPACE);
78   
79    private static Map<String, String> actionMap;
80   
81    /**
82    * Used to convert a string into a proper Document Reference.
83    */
84    private DocumentReferenceResolver<String> currentMixedDocumentReferenceResolver = Utils.getComponent(
85    DocumentReferenceResolver.TYPE_STRING, "currentmixed");
86   
87    /**
88    * Used to convert a proper Document Name to string.
89    */
90    private EntityReferenceSerializer<String> entityReferenceSerializer = Utils
91    .getComponent(EntityReferenceSerializer.TYPE_STRING);
92   
 
93  76 toggle protected void logAllow(String username, String page, String action, String info)
94    {
95  76 LOGGER.debug("Access has been granted for ([{}], [{}], [{}]): [{}]", username, page, action, info);
96    }
97   
 
98  23 toggle protected void logDeny(String username, String page, String action, String info)
99    {
100  23 LOGGER.info("Access has been denied for ([{}], [{}], [{}]): [{}]", username, page, action, info);
101    }
102   
 
103  0 toggle protected void logDeny(String name, String resourceKey, String accessLevel, String info, Exception e)
104    {
105  0 LOGGER.debug("Access has been denied for ([{}], [{}], [{}]) at [{}]", name, resourceKey, accessLevel, info, e);
106    }
107   
 
108  0 toggle @Override
109    public List<String> listAllLevels(XWikiContext context) throws XWikiException
110    {
111  0 return new ArrayList<String>(ALLLEVELS);
112    }
113   
 
114  2 toggle public String getRight(String action)
115    {
116  2 if (actionMap == null) {
117  1 actionMap = new HashMap<String, String>();
118  1 actionMap.put("login", "login");
119  1 actionMap.put("logout", "login");
120  1 actionMap.put("loginerror", "login");
121  1 actionMap.put("loginsubmit", "login");
122  1 actionMap.put("view", "view");
123  1 actionMap.put("viewrev", "view");
124  1 actionMap.put("get", "view");
125  1 actionMap.put("downloadrev", "view");
126  1 actionMap.put("plain", "view");
127  1 actionMap.put("raw", "view");
128  1 actionMap.put("attach", "view");
129  1 actionMap.put("charting", "view");
130  1 actionMap.put("skin", "view");
131  1 actionMap.put("download", "view");
132  1 actionMap.put("dot", "view");
133  1 actionMap.put("svg", "view");
134  1 actionMap.put("pdf", "view");
135  1 actionMap.put("delete", "delete");
136  1 actionMap.put("deletespace", "admin");
137  1 actionMap.put("deleteversions", "admin");
138  1 actionMap.put("undelete", "undelete");
139  1 actionMap.put("reset", "delete");
140  1 actionMap.put("commentadd", "comment");
141  1 actionMap.put("commentsave", "comment");
142  1 actionMap.put("register", "register");
143  1 actionMap.put("redirect", "view");
144  1 actionMap.put("admin", "admin");
145  1 actionMap.put("export", "view");
146  1 actionMap.put("import", "admin");
147  1 actionMap.put("jsx", "view");
148  1 actionMap.put("ssx", "view");
149  1 actionMap.put("tex", "view");
150  1 actionMap.put("create", "edit");
151  1 actionMap.put("temp", "view");
152  1 actionMap.put("unknown", "view");
153    }
154   
155  2 String right = actionMap.get(action);
156  2 if (right == null) {
157  1 return "edit";
158    } else {
159  1 return right;
160    }
161    }
162   
 
163  2 toggle @Override
164    public boolean checkAccess(String action, XWikiDocument doc, XWikiContext context) throws XWikiException
165    {
166  2 LOGGER.debug("checkAccess for [{}], [{}]", action, doc);
167   
168  2 String username = null;
169  2 XWikiUser user = null;
170  2 boolean needsAuth = false;
171  2 String right = getRight(action);
172   
173  2 if (right.equals("login")) {
174  0 user = context.getWiki().checkAuth(context);
175  0 if (user == null) {
176  0 username = XWikiRightService.GUEST_USER_FULLNAME;
177    } else {
178  0 username = user.getUser();
179    }
180   
181    // Save the user
182  0 context.setUser(username);
183  0 logAllow(username, doc.getFullName(), action, "login/logout pages");
184   
185  0 return true;
186    }
187   
188  2 if (right.equals("delete")) {
189  0 user = context.getWiki().checkAuth(context);
190  0 String creator = doc.getCreator();
191  0 if ((user != null) && (user.getUser() != null) && (creator != null)) {
192  0 if (user.getUser().equals(creator)) {
193  0 context.setUser(user.getUser());
194   
195  0 return true;
196    }
197    }
198    }
199   
200    // We do not need to authenticate twice
201    // This seems to cause a problem in virtual wikis
202  2 user = context.getXWikiUser();
203  2 if (user == null) {
204  1 needsAuth = needsAuth(right, context);
205  1 try {
206  1 if (context.getMode() != XWikiContext.MODE_XMLRPC) {
207  1 user = context.getWiki().checkAuth(context);
208    } else {
209  0 user = new XWikiUser(context.getUser());
210    }
211   
212  1 if ((user == null) && (needsAuth)) {
213  0 logDeny("unauthentified", doc.getFullName(), action, "Authentication needed");
214  0 if (context.getRequest() != null) {
215  0 if (!context.getWiki().Param("xwiki.hidelogin", "false").equalsIgnoreCase("true")) {
216  0 context.getWiki().getAuthService().showLogin(context);
217    }
218    }
219   
220  0 return false;
221    }
222    } catch (XWikiException e) {
223  0 if (needsAuth) {
224  0 throw e;
225    }
226    }
227   
228  1 if (user == null) {
229  0 username = XWikiRightService.GUEST_USER_FULLNAME;
230    } else {
231  1 username = user.getUser();
232    }
233   
234    // Save the user
235  1 context.setUser(username);
236    } else {
237  1 username = user.getUser();
238    }
239   
240    // Check Rights
241  2 try {
242    // Verify access rights and return if ok
243  2 String docname;
244  2 if (context.getWikiId() != null) {
245  2 docname = context.getWikiId() + ":" + doc.getFullName();
246  2 if (username.indexOf(":") == -1) {
247  2 username = context.getWikiId() + ":" + username;
248    }
249    } else {
250  0 docname = doc.getFullName();
251    }
252   
253  2 if (context.getWiki().getRightService().hasAccessLevel(right, username, docname, context)) {
254  0 logAllow(username, docname, action, "access manager granted right");
255   
256  0 return true;
257    }
258    } catch (Exception e) {
259    // This should not happen..
260  0 logDeny(username, doc.getFullName(), action, "access manager exception " + e.getMessage());
261  0 e.printStackTrace();
262   
263  0 return false;
264    }
265   
266  2 if (user == null) {
267    // Denied Guest need to be authenticated
268  0 logDeny("unauthentified", doc.getFullName(), action, "Guest has been denied");
269  0 if (context.getRequest() != null
270    && !context.getWiki().Param("xwiki.hidelogin", "false").equalsIgnoreCase("true")) {
271  0 context.getWiki().getAuthService().showLogin(context);
272    }
273   
274  0 return false;
275    } else {
276  2 logDeny(username, doc.getFullName(), action, "access manager denied right");
277   
278  2 return false;
279    }
280    }
281   
 
282  21 toggle private boolean needsAuth(String right, XWikiContext context)
283    {
284  21 boolean needsAuth = false;
285   
286  21 try {
287  21 needsAuth =
288    context.getWiki().getXWikiPreference("authenticate_" + right, "", context).toLowerCase().equals("yes");
289    } catch (Exception e) {
290    }
291   
292  21 try {
293  21 needsAuth |= (context.getWiki().getXWikiPreferenceAsInt("authenticate_" + right, 0, context) == 1);
294    } catch (Exception e) {
295    }
296   
297  21 try {
298  21 needsAuth |=
299    context.getWiki().getSpacePreference("authenticate_" + right, "", context).toLowerCase().equals("yes");
300    } catch (Exception e) {
301    }
302   
303  21 try {
304  21 needsAuth |= (context.getWiki().getSpacePreferenceAsInt("authenticate_" + right, 0, context) == 1);
305    } catch (Exception e) {
306    }
307   
308  21 return needsAuth;
309    }
310   
 
311  63 toggle @Override
312    public boolean hasAccessLevel(String right, String username, String docname, XWikiContext context)
313    throws XWikiException
314    {
315  63 try {
316  63 return hasAccessLevel(right, username, docname, true, context);
317    } catch (XWikiException e) {
318  0 return false;
319    }
320    }
321   
 
322  615 toggle public boolean checkRight(String userOrGroupName, XWikiDocument doc, String accessLevel, boolean user,
323    boolean allow, boolean global, XWikiContext context) throws XWikiRightNotFoundException, XWikiException
324    {
325  615 if (!global && ("admin".equals(accessLevel))) {
326    // Admin rights do not exist at document level.
327  26 throw new XWikiRightNotFoundException();
328    }
329   
330  589 EntityReference rightClassReference = global ? GLOBALRIGHTCLASS_REFERENCE : RIGHTCLASS_REFERENCE;
331  589 String fieldName = user ? "users" : "groups";
332  589 boolean found = false;
333   
334    // Here entity is either a user or a group
335  589 DocumentReference userOrGroupDocumentReference =
336    this.currentMixedDocumentReferenceResolver.resolve(userOrGroupName);
337  589 String prefixedFullName = this.entityReferenceSerializer.serialize(userOrGroupDocumentReference);
338  589 String shortname = userOrGroupName;
339  589 int i0 = userOrGroupName.indexOf(":");
340  589 if (i0 != -1) {
341  527 shortname = userOrGroupName.substring(i0 + 1);
342    }
343   
344  589 if (LOGGER.isDebugEnabled()) {
345  0 LOGGER.debug("Checking right: [{}], [{}], [{}], [{}], [{}], [{}]", userOrGroupName, doc.getFullName(),
346    accessLevel, user, allow, global);
347    }
348   
349  589 List<BaseObject> rightObjects = doc.getXObjects(rightClassReference);
350  589 if (rightObjects != null) {
351  350 if (LOGGER.isDebugEnabled()) {
352  0 LOGGER.debug("Checking objects [{}]", rightObjects.size());
353    }
354   
355  657 for (int i = 0; i < rightObjects.size(); i++) {
356  369 LOGGER.debug("Checking object [{}]", i);
357   
358  369 BaseObject bobj = rightObjects.get(i);
359   
360  369 if (bobj == null) {
361  0 LOGGER.debug("Bypass object [{}]", i);
362  0 continue;
363    }
364   
365  369 String users = bobj.getStringValue(fieldName);
366  369 String levels = bobj.getStringValue("levels");
367  369 boolean allowdeny = (bobj.getIntValue("allow") == 1);
368   
369  369 if (allowdeny == allow) {
370  272 LOGGER.debug("Checking match: [{}] in [{}]", accessLevel, levels);
371   
372  272 String[] levelsarray = StringUtils.split(levels, " ,|");
373  272 if (ArrayUtils.contains(levelsarray, accessLevel)) {
374  112 LOGGER.debug("Found a right for [{}]", allow);
375  112 found = true;
376   
377  112 LOGGER.debug("Checking match: [{}] in [{}]", userOrGroupName, users);
378   
379  112 String[] userarray = GroupsClass.getListFromString(users).toArray(new String[0]);
380   
381  185 for (int ii = 0; ii < userarray.length; ii++) {
382  73 String value = userarray[ii];
383  73 if (value.indexOf(".") == -1) {
384  7 userarray[ii] = "XWiki." + value;
385    }
386    }
387   
388  112 if (LOGGER.isDebugEnabled()) {
389  0 LOGGER.debug("Checking match: [{}] in [{}]", userOrGroupName,
390    StringUtils.join(userarray, ","));
391    }
392   
393    // In the case where the document database and the user database is the same
394    // then we allow the usage of the short name, otherwise the fully qualified
395    // name is requested
396  112 if (doc.getWikiName().equals(userOrGroupDocumentReference.getWikiReference().getName())) {
397  58 if (ArrayUtils.contains(userarray, shortname)) {
398  23 LOGGER.debug("Found matching right in [{}] for [{}]", users, shortname);
399  23 return true;
400    }
401   
402    // We should also allow to skip "XWiki." from the usernames and group
403    // lists
404  35 String veryshortname = shortname.substring(shortname.indexOf(".") + 1);
405  35 if (ArrayUtils.contains(userarray, veryshortname)) {
406  0 LOGGER.debug("Found matching right in [{}] for [{}]", users, shortname);
407  0 return true;
408    }
409    }
410   
411  89 if ((context.getWikiId() != null) && (ArrayUtils.contains(userarray, userOrGroupName))) {
412  39 LOGGER.debug("Found matching right in [{}] for [{}]", users, userOrGroupName);
413  39 return true;
414    }
415   
416  50 LOGGER.debug("Failed match: [{}] in [{}]", userOrGroupName, users);
417    }
418    } else {
419  97 LOGGER.debug("Bypass object [{}] because wrong allow/deny", i);
420    }
421    }
422    }
423   
424  527 LOGGER.debug("Searching for matching rights at group level");
425   
426    // Didn't found right at this level.. Let's go to group level
427  527 Map<String, Collection<String>> grouplistcache = (Map<String, Collection<String>>) context.get("grouplist");
428  527 if (grouplistcache == null) {
429  21 grouplistcache = new HashMap<String, Collection<String>>();
430  21 context.put("grouplist", grouplistcache);
431    }
432   
433  527 Collection<String> grouplist = new HashSet<String>();
434   
435    // Get member groups from document's wiki
436  527 addMemberGroups(doc.getWikiName(), prefixedFullName, userOrGroupDocumentReference, grouplist, context);
437   
438    // Get member groups from member's wiki
439  527 if (!context.getWikiId().equalsIgnoreCase(userOrGroupDocumentReference.getWikiReference().getName())) {
440  294 addMemberGroups(userOrGroupDocumentReference.getWikiReference().getName(), prefixedFullName,
441    userOrGroupDocumentReference, grouplist, context);
442    }
443   
444  527 if (LOGGER.isDebugEnabled()) {
445  0 LOGGER.debug("Searching for matching rights for [{}] groups: [{}]", grouplist.size(), grouplist);
446    }
447   
448  527 for (String group : grouplist) {
449  213 try {
450    // We need to construct the full group name to make sure the groups are
451    // handled separately
452  213 boolean result = checkRight(group, doc, accessLevel, false, allow, global, context);
453  29 if (result) {
454  17 return true;
455    }
456    } catch (XWikiRightNotFoundException e) {
457    } catch (Exception e) {
458  0 LOGGER.error("Failed to check right [{}] for group [{}] on document [ΒΆ}]", accessLevel, group,
459    doc.getPrefixedFullName(), e);
460    }
461    }
462   
463  510 LOGGER.debug("Finished searching for rights for [{}]: [{}]", userOrGroupName, found);
464   
465  510 if (found) {
466  33 return false;
467    } else {
468  477 throw new XWikiRightNotFoundException();
469    }
470    }
471   
 
472  821 toggle private void addMemberGroups(String wiki, String prefixedFullName, DocumentReference userOrGroupDocumentReference,
473    Collection<String> grouplist, XWikiContext context) throws XWikiException
474    {
475  821 XWikiGroupService groupService = context.getWiki().getGroupService(context);
476   
477  821 Map<String, Collection<String>> grouplistcache = (Map<String, Collection<String>>) context.get("grouplist");
478  821 if (grouplistcache == null) {
479  0 grouplistcache = new HashMap<String, Collection<String>>();
480  0 context.put("grouplist", grouplistcache);
481    }
482   
483    // the key is for the entity <code>prefixedFullName</code> in current wiki
484  821 String key = wiki + ":" + prefixedFullName;
485   
486  821 Collection<String> tmpGroupList = grouplistcache.get(key);
487  821 if (tmpGroupList == null) {
488  47 String currentWiki = context.getWikiId();
489  47 try {
490  47 context.setWikiId(wiki);
491   
492  47 Collection<DocumentReference> groupReferences =
493    groupService.getAllGroupsReferencesForMember(userOrGroupDocumentReference, 0, 0, context);
494   
495  47 tmpGroupList = new ArrayList<String>(groupReferences.size());
496  47 for (DocumentReference groupReference : groupReferences) {
497  12 tmpGroupList.add(this.entityReferenceSerializer.serialize(groupReference));
498    }
499    } catch (Exception e) {
500  0 LOGGER.error("Failed to get groups for user or group [{}] in wiki [{}]", prefixedFullName, wiki, e);
501  0 tmpGroupList = Collections.emptyList();
502    } finally {
503  47 context.setWikiId(currentWiki);
504    }
505   
506  47 grouplistcache.put(key, tmpGroupList);
507    }
508   
509  821 grouplist.addAll(tmpGroupList);
510    }
511   
 
512  88 toggle public boolean hasAccessLevel(String accessLevel, String userOrGroupName, String entityReference, boolean user,
513    XWikiContext context) throws XWikiException
514    {
515  88 LOGGER.debug("hasAccessLevel for [{}], [{}], [{}]", accessLevel, userOrGroupName, entityReference);
516   
517  88 DocumentReference userOrGroupNameReference =
518    this.currentMixedDocumentReferenceResolver.resolve(userOrGroupName);
519   
520  88 if (!userOrGroupNameReference.getName().equals(XWikiRightService.GUEST_USER) && context.getWikiId() != null) {
521    // Make sure to have the prefixed full name of the user or group
522  68 userOrGroupName =
523    this.entityReferenceSerializer.serialize(this.currentMixedDocumentReferenceResolver.resolve(
524    userOrGroupName, DEFAULTUSERSPACE));
525   
526    // Make sure to have the prefixed full name of the resource
527  68 entityReference =
528    this.entityReferenceSerializer.serialize(this.currentMixedDocumentReferenceResolver
529    .resolve(entityReference));
530    }
531   
532  88 boolean deny = false;
533  88 boolean allow = false;
534  88 boolean allow_found = false;
535  88 boolean deny_found = false;
536  88 boolean isReadOnly = context.getWiki().isReadOnly();
537  88 String database = context.getWikiId();
538  88 XWikiDocument currentdoc = null;
539   
540  88 if (isReadOnly) {
541  0 if ("edit".equals(accessLevel) || "delete".equals(accessLevel) || "undelete".equals(accessLevel)
542    || "comment".equals(accessLevel) || "register".equals(accessLevel)) {
543  0 logDeny(userOrGroupName, entityReference, accessLevel, "server in read-only mode");
544   
545  0 return false;
546    }
547    }
548   
549  88 if (userOrGroupNameReference.getName().equals(XWikiRightService.GUEST_USER)) {
550  20 if (needsAuth(accessLevel, context)) {
551  0 return false;
552    }
553    }
554   
555    // Fast return for delete right: allow the creator to delete the document
556  88 if (accessLevel.equals("delete") && user) {
557  4 currentdoc = context.getWiki().getDocument(entityReference, context);
558  4 DocumentReference creator = currentdoc.getCreatorReference();
559  4 if (ObjectUtils.equals(userOrGroupNameReference, creator)) {
560  1 logAllow(userOrGroupName, entityReference, accessLevel, "delete right from document ownership");
561  1 return true;
562    }
563    }
564   
565  87 allow = isSuperAdminOrProgramming(userOrGroupName, entityReference, accessLevel, user, context);
566  87 if ((allow == true) || (accessLevel.equals("programming"))) {
567  16 return allow;
568    }
569   
570  71 try {
571  71 currentdoc = currentdoc == null ? context.getWiki().getDocument(entityReference, context) : currentdoc;
572   
573  71 DocumentReference docReference = currentdoc.getDocumentReference();
574   
575  71 if (accessLevel.equals("edit")
576    && (docReference.getName().equals("WebPreferences") || (docReference.getLastSpaceReference().getName()
577    .equals("XWiki") && docReference.getName().equals("XWikiPreferences")))) {
578    // Since edit rights on these documents would be sufficient for a user to elevate himself to
579    // admin or even programmer, we will instead check for admin access on these documents.
580    // See http://jira.xwiki.org/browse/XWIKI-6987 and http://jira.xwiki.org/browse/XWIKI-2184.
581  4 accessLevel = "admin";
582    }
583   
584    // We need to make sure we are in the context of the document which rights is being checked
585  71 context.setWikiId(currentdoc.getDatabase());
586   
587    // Verify Wiki Owner
588  71 String wikiOwner = context.getWiki().getWikiOwner(currentdoc.getDatabase(), context);
589  71 if (wikiOwner != null) {
590  36 if (wikiOwner.equals(userOrGroupName)) {
591  4 logAllow(userOrGroupName, entityReference, accessLevel, "admin level from wiki ownership");
592   
593  4 return true;
594    }
595    }
596   
597  67 XWikiDocument entityWikiPreferences = context.getWiki().getDocument(XWIKIPREFERENCES_REFERENCE, context);
598   
599    // Verify XWiki register right
600  67 if (accessLevel.equals("register")) {
601  1 try {
602  1 allow = checkRight(userOrGroupName, entityWikiPreferences, "register", user, true, true, context);
603  0 if (allow) {
604  0 logAllow(userOrGroupName, entityReference, accessLevel, "register level");
605   
606  0 return true;
607    } else {
608  0 logDeny(userOrGroupName, entityReference, accessLevel, "register level");
609   
610  0 return false;
611    }
612    } catch (XWikiRightNotFoundException e) {
613  1 try {
614  1 deny =
615    checkRight(userOrGroupName, entityWikiPreferences, "register", user, false, true, context);
616  0 if (deny) {
617  0 return false;
618    }
619    } catch (XWikiRightNotFoundException e1) {
620    }
621    }
622   
623  1 logAllow(userOrGroupName, entityReference, accessLevel, "register level (no right found)");
624   
625  1 return true;
626    }
627   
628  66 int maxRecursiveSpaceChecks = context.getWiki().getMaxRecursiveSpaceChecks(context);
629  66 boolean isSuperUser =
630    isSuperUser(accessLevel, userOrGroupName, entityReference, user, entityWikiPreferences,
631    maxRecursiveSpaceChecks, context);
632  66 if (isSuperUser) {
633  0 logAllow(userOrGroupName, entityReference, accessLevel, "admin level");
634   
635  0 return true;
636    }
637   
638    // check has deny rights
639  66 if (hasDenyRights()) {
640    // First check if this document is denied to the specific user
641  66 entityReference = Util.getName(entityReference, context);
642  66 try {
643  66 currentdoc =
644  66 currentdoc == null ? context.getWiki().getDocument(entityReference, context) : currentdoc;
645  66 deny = checkRight(userOrGroupName, currentdoc, accessLevel, user, false, false, context);
646  8 deny_found = true;
647  8 if (deny) {
648  8 logDeny(userOrGroupName, entityReference, accessLevel, "document level");
649  8 return false;
650    }
651    } catch (XWikiRightNotFoundException e) {
652    }
653    }
654   
655  58 try {
656  58 currentdoc = currentdoc == null ? context.getWiki().getDocument(entityReference, context) : currentdoc;
657  58 allow = checkRight(userOrGroupName, currentdoc, accessLevel, user, true, false, context);
658  0 allow_found = true;
659  0 if (allow) {
660  0 logAllow(userOrGroupName, entityReference, accessLevel, "document level");
661   
662  0 return true;
663    }
664    } catch (XWikiRightNotFoundException e) {
665    }
666   
667    // Check if this document is denied/allowed
668    // through the space WebPreferences Global Rights
669   
670  58 String space = currentdoc.getSpace();
671  58 ArrayList<String> spacesChecked = new ArrayList<String>();
672  58 int recursiveSpaceChecks = 0;
673  116 while ((space != null) && (recursiveSpaceChecks <= maxRecursiveSpaceChecks)) {
674    // Add one to the recursive space checks
675  58 recursiveSpaceChecks++;
676    // add to list of spaces already checked
677  58 spacesChecked.add(space);
678  58 XWikiDocument webdoc = context.getWiki().getDocument(space, "WebPreferences", context);
679  58 if (!webdoc.isNew()) {
680  1 if (hasDenyRights()) {
681  1 try {
682  1 deny = checkRight(userOrGroupName, webdoc, accessLevel, user, false, true, context);
683  0 deny_found = true;
684  0 if (deny) {
685  0 logDeny(userOrGroupName, entityReference, accessLevel, "web level");
686   
687  0 return false;
688    }
689    } catch (XWikiRightNotFoundException e) {
690    }
691    }
692   
693    // If a right was found at the previous level
694    // then we cannot check the web rights anymore
695  1 if (!allow_found) {
696  1 try {
697  1 allow = checkRight(userOrGroupName, webdoc, accessLevel, user, true, true, context);
698  1 allow_found = true;
699  1 if (allow) {
700  0 logAllow(userOrGroupName, entityReference, accessLevel, "web level");
701   
702  0 return true;
703    }
704    } catch (XWikiRightNotFoundException e) {
705    }
706    }
707   
708    // find the parent web to check rights on it
709  1 space = webdoc.getStringValue("XWiki.XWikiPreferences", "parent");
710  1 if ((space == null) || (space.trim().equals("")) || spacesChecked.contains(space)) {
711    // no parent space or space already checked (recursive loop). let's finish
712    // the loop
713  1 space = null;
714    }
715    } else {
716    // let's finish the loop
717  57 space = null;
718    }
719    }
720   
721    // Check if this document is denied/allowed
722    // through the XWiki.XWikiPreferences Global Rights
723  58 if (hasDenyRights()) {
724  58 try {
725  58 deny = checkRight(userOrGroupName, entityWikiPreferences, accessLevel, user, false, true, context);
726  7 deny_found = true;
727  7 if (deny) {
728  7 logDeny(userOrGroupName, entityReference, accessLevel, "xwiki level");
729   
730  7 return false;
731    }
732    } catch (XWikiRightNotFoundException e) {
733    }
734    }
735   
736    // If a right was found at the document or web level
737    // then we cannot check the web rights anymore
738  51 if (!allow_found) {
739  50 try {
740  50 allow = checkRight(userOrGroupName, entityWikiPreferences, accessLevel, user, true, true, context);
741  33 allow_found = true;
742  33 if (allow) {
743  31 logAllow(userOrGroupName, entityReference, accessLevel, "xwiki level");
744   
745  31 return true;
746    }
747    } catch (XWikiRightNotFoundException e) {
748    }
749    }
750   
751    // If neither doc, web or topic had any allowed ACL
752    // and that all users that were not denied
753    // should be allowed.
754  20 if (!allow_found) {
755    // Delete must be denied by default.
756  17 if ("delete".equals(accessLevel)) {
757  2 if (hasAccessLevel("admin", userOrGroupName, entityReference, user, context)) {
758  2 logAllow(userOrGroupName, entityReference, accessLevel,
759    "admin rights imply delete on empty wiki");
760  2 return true;
761    }
762  0 logDeny(userOrGroupName, entityReference, accessLevel,
763    "global level (delete right must be explicit)");
764   
765  0 return false;
766    } else {
767  15 logAllow(userOrGroupName, entityReference, accessLevel, "global level (no restricting right)");
768   
769  15 return true;
770    }
771    } else {
772  3 logDeny(userOrGroupName, entityReference, accessLevel, "global level (restricting right was found)");
773   
774  3 return false;
775    }
776   
777    } catch (XWikiException e) {
778  0 logDeny(userOrGroupName, entityReference, accessLevel, "global level (exception)", e);
779  0 e.printStackTrace();
780   
781  0 return false;
782    } finally {
783  71 context.setWikiId(database);
784    }
785    }
786   
 
787  125 toggle private boolean hasDenyRights()
788    {
789  125 return true;
790    }
791   
792    /**
793    * @param username Any flavor of username. Examples: "xwiki:XWiki.superadmin", "XWiki.superAdmin", "superadmin", etc
794    * @return true if the username is that of the superadmin (whatever the case) or false otherwise
795    */
796    // TODO: this method is a candidate for the the XWikiRightService API.
 
797  97 toggle private boolean isSuperAdmin(String username)
798    {
799    // Note 1: we use the default document reference resolver here but it doesn't matter since we only care about
800    // the resolved page name.
801    // Note 2: we use a resolver since the passed username could contain the wiki and/or space too and we want
802    // to retrieve only the page name
803  97 DocumentReference userReference =
804    Utils.<DocumentReferenceResolver<String>>getComponent(DocumentReferenceResolver.TYPE_STRING).resolve(
805    username);
806  97 return StringUtils.equalsIgnoreCase(userReference.getName(), SUPERADMIN_USER);
807    }
808   
 
809  99 toggle private boolean isSuperAdminOrProgramming(String name, String resourceKey, String accessLevel, boolean user,
810    XWikiContext context) throws XWikiException
811    {
812  99 if (name == null) {
813  2 return false;
814    }
815   
816  97 String database = context.getWikiId();
817  97 boolean allow;
818   
819  97 if (isSuperAdmin(name)) {
820  7 logAllow(name, resourceKey, accessLevel, "super admin level");
821  7 return true;
822    }
823   
824  90 try {
825    // The master user and programming rights are checked in the main wiki
826  90 context.setWikiId(context.getMainXWiki());
827  90 XWikiDocument xwikimasterdoc = context.getWiki().getDocument(XWIKIPREFERENCES_REFERENCE, context);
828    // Verify XWiki Master super user
829  90 try {
830  90 allow = checkRight(name, xwikimasterdoc, "admin", true, true, true, context);
831  27 if (allow) {
832  10 logAllow(name, resourceKey, accessLevel, "master admin level");
833  10 return true;
834    }
835    } catch (XWikiRightNotFoundException e) {
836    }
837   
838    // Verify XWiki programming right
839  80 if (accessLevel.equals("programming")) {
840    // Programming right can only been given if user is from main wiki
841  9 if (!name.startsWith(context.getMainXWiki() + ":")) {
842  1 return false;
843    }
844   
845  8 try {
846  8 allow = checkRight(name, xwikimasterdoc, "programming", user, true, true, context);
847  6 if (allow) {
848  5 logAllow(name, resourceKey, accessLevel, "programming level");
849   
850  5 return true;
851    } else {
852  1 logDeny(name, resourceKey, accessLevel, "programming level");
853   
854  1 return false;
855    }
856    } catch (XWikiRightNotFoundException e) {
857    }
858   
859  2 logDeny(name, resourceKey, accessLevel, "programming level (no right found)");
860   
861  2 return false;
862    }
863    } finally {
864    // The next rights are checked in the virtual wiki
865  90 context.setWikiId(database);
866    }
867   
868  71 return false;
869    }
870   
 
871  66 toggle private boolean isSuperUser(String accessLevel, String name, String resourceKey, boolean user,
872    XWikiDocument xwikidoc, int maxRecursiveSpaceChecks, XWikiContext context) throws XWikiException
873    {
874  66 boolean allow;
875   
876    // Verify XWiki super user
877  66 try {
878  66 allow = checkRight(name, xwikidoc, "admin", user, true, true, context);
879  0 if (allow) {
880  0 logAllow(name, resourceKey, accessLevel, "admin level");
881   
882  0 return true;
883    }
884    } catch (XWikiRightNotFoundException e) {
885    }
886   
887  66 XWikiDocument documentName = new XWikiDocument();
888  66 documentName.setFullName(resourceKey);
889   
890    // Verify Web super user
891  66 String space = documentName.getSpace();
892  66 ArrayList<String> spacesChecked = new ArrayList<String>();
893  66 int recursiveSpaceChecks = 0;
894  132 while ((space != null) && (recursiveSpaceChecks <= maxRecursiveSpaceChecks)) {
895    // Add one to the recursive space checks
896  66 recursiveSpaceChecks++;
897    // add to list of spaces already checked
898  66 spacesChecked.add(space);
899  66 XWikiDocument webdoc = context.getWiki().getDocument(space, "WebPreferences", context);
900  66 if (!webdoc.isNew()) {
901  1 try {
902  1 allow = checkRight(name, webdoc, "admin", user, true, true, context);
903  0 if (allow) {
904  0 logAllow(name, resourceKey, accessLevel, "web admin level");
905  0 return true;
906    }
907    } catch (XWikiRightNotFoundException e) {
908    }
909   
910    // find the parent web to check rights on it
911  1 space = webdoc.getStringValue("XWiki.XWikiPreferences", "parent");
912  1 if ((space == null) || (space.trim().equals("")) || spacesChecked.contains(space)) {
913    // no parent space or space already checked (recursive loop). let's finish the
914    // loop
915  1 space = null;
916    }
917    } else {
918  65 space = null;
919    }
920    }
921   
922  66 return false;
923    }
924   
 
925  18 toggle @Override
926    public boolean hasProgrammingRights(XWikiContext context)
927    {
928    // Once dropPermissions has been called, the document in the
929    // context cannot have programming permission.
930  18 if (context.hasDroppedPermissions()) {
931  3 return false;
932    }
933  15 XWikiDocument sdoc = (XWikiDocument) context.get("sdoc");
934  15 if (sdoc == null) {
935  12 sdoc = context.getDoc();
936    }
937   
938  15 return hasProgrammingRights(sdoc, context);
939    }
940   
 
941  15 toggle @Override
942    public boolean hasProgrammingRights(XWikiDocument doc, XWikiContext context)
943    {
944  15 try {
945  15 if (doc == null) {
946    // If no context document is set, then check the rights of the current user
947  12 return isSuperAdminOrProgramming(this.entityReferenceSerializer.serialize(context.getUserReference()),
948    null, "programming", true, context);
949    }
950   
951  3 String username = doc.getContentAuthor();
952   
953  3 if (username == null) {
954  0 return false;
955    }
956   
957  3 String docname;
958  3 if (doc.getDatabase() != null) {
959  3 docname = doc.getDatabase() + ":" + doc.getFullName();
960  3 if (username.indexOf(":") == -1) {
961  3 username = doc.getDatabase() + ":" + username;
962    }
963    } else {
964  0 docname = doc.getFullName();
965    }
966   
967    // programming rights can only been given for user of the main wiki
968    // FIXME: Isn't this wrong? The main db is context.getMainWikiName(), not context.getWiki().getDatabase()
969    // (which is the current db).
970  3 String maindb = context.getWiki().getDatabase();
971  3 if ((maindb == null) || (!username.startsWith(maindb))) {
972  0 return false;
973    }
974   
975  3 return hasAccessLevel("programming", username, docname, context);
976    } catch (Exception e) {
977  0 LOGGER.error("Failed to check programming right for document [{}]", doc.getPrefixedFullName(), e);
978   
979  0 return false;
980    }
981    }
982   
 
983  1 toggle @Override
984    public boolean hasAdminRights(XWikiContext context)
985    {
986  1 boolean hasAdmin = hasWikiAdminRights(context);
987   
988  1 if (!hasAdmin) {
989  0 try {
990  0 hasAdmin =
991    hasAccessLevel("admin", context.getUser(), context.getDoc().getSpace() + ".WebPreferences", context);
992    } catch (Exception e) {
993  0 LOGGER.error("Failed to check space admin right for user [{}]", context.getUser(), e);
994    }
995    }
996   
997  1 return hasAdmin;
998    }
999   
 
1000  2 toggle @Override
1001    public boolean hasWikiAdminRights(XWikiContext context)
1002    {
1003  2 try {
1004  2 return hasAccessLevel("admin", context.getUser(), "XWiki.XWikiPreferences", context);
1005    } catch (Exception e) {
1006  0 LOGGER.error("Failed to check wiki admin right for user [{}]", context.getUser(), e);
1007  0 return false;
1008    }
1009    }
1010   
1011    }