1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.security.authorization.internal

File DefaultSecurityEntryReader.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

26
80
10
2
335
194
32
0.4
8
5
3.2

Classes

Class Line # Actions
DefaultSecurityEntryReader 63 76 0% 29 8
0.926605592.7%
DefaultSecurityEntryReader.InternalSecurityRuleEntry 96 4 0% 3 0
1.0100%
 

Contributing tests

This file is covered by 18 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 org.xwiki.security.authorization.internal;
21   
22    import java.util.ArrayList;
23    import java.util.Collection;
24    import java.util.Collections;
25    import java.util.List;
26    import java.util.Set;
27   
28    import javax.inject.Inject;
29    import javax.inject.Named;
30    import javax.inject.Singleton;
31   
32    import org.xwiki.component.annotation.Component;
33    import org.xwiki.context.Execution;
34    import org.xwiki.model.EntityType;
35    import org.xwiki.model.reference.DocumentReference;
36    import org.xwiki.model.reference.DocumentReferenceResolver;
37    import org.xwiki.model.reference.SpaceReference;
38    import org.xwiki.model.reference.WikiReference;
39    import org.xwiki.security.SecurityReference;
40    import org.xwiki.security.authorization.AuthorizationException;
41    import org.xwiki.security.authorization.EntityTypeNotSupportedException;
42    import org.xwiki.security.authorization.Right;
43    import org.xwiki.security.authorization.RightSet;
44    import org.xwiki.security.authorization.RuleState;
45    import org.xwiki.security.authorization.SecurityEntryReader;
46    import org.xwiki.security.authorization.SecurityRule;
47    import org.xwiki.security.authorization.SecurityRuleEntry;
48    import org.xwiki.security.internal.XWikiConstants;
49   
50    import com.xpn.xwiki.XWikiContext;
51    import com.xpn.xwiki.XWikiException;
52    import com.xpn.xwiki.doc.XWikiDocument;
53    import com.xpn.xwiki.objects.BaseObject;
54   
55    /**
56    * The default implementation of the security rules reader, which reads rules from documents in a wiki.
57    *
58    * @version $Id: 9fdfc015c9b9133f4e6999ec119f34d1f137a106 $
59    * @since 4.0M2
60    */
61    @Component
62    @Singleton
 
63    public class DefaultSecurityEntryReader implements SecurityEntryReader
64    {
65    /** A security rules to deny everyone the edit right by allowing edit to no one. */
66    private static final SecurityRule DENY_EDIT = new AllowEditToNoOneRule();
67   
68    /** Right set allowed for main wiki owner. */
69    private static final Set<Right> MAINWIKIOWNER_RIGHTS = new RightSet(Right.PROGRAM);
70   
71    /** Right set allowed for wiki owner. */
72    private static final Set<Right> OWNER_RIGHTS = new RightSet(Right.ADMIN);
73   
74    /** Right set allowed for document creators. */
75    private static final Set<Right> CREATOR_RIGHTS = new RightSet(Right.CREATOR);
76   
77    /** Resolver for user and group names. */
78    @Inject
79    @Named("user")
80    private DocumentReferenceResolver<String> resolver;
81   
82    /** Execution object. */
83    @Inject
84    private Execution execution;
85   
86    /**
87    * @return the current {@code XWikiContext}
88    */
 
89  3334 toggle private XWikiContext getXWikiContext() {
90  3334 return ((XWikiContext) execution.getContext().getProperty(XWikiContext.EXECUTIONCONTEXT_KEY));
91    }
92   
93    /**
94    * Internal implementation of the SecurityRuleEntry.
95    */
 
96    private final class InternalSecurityRuleEntry extends AbstractSecurityRuleEntry
97    {
98    /** Reference of the related entity. */
99    private final SecurityReference reference;
100   
101    /** The list of objects. */
102    private final Collection<SecurityRule> rules;
103   
104    /**
105    * @param reference reference of the related entity
106    * @param rules collection of security rules applied on the entity.
107    */
 
108  2060 toggle private InternalSecurityRuleEntry(SecurityReference reference, Collection<SecurityRule> rules)
109    {
110  2061 this.reference = reference;
111  2061 this.rules = Collections.unmodifiableCollection(rules);
112    }
113   
114    /**
115    * @return the reference of the related entity
116    */
 
117  25887 toggle @Override
118    public SecurityReference getReference()
119    {
120  25887 return reference;
121    }
122   
123    /**
124    * @return all rules available for this entity
125    */
 
126  125037 toggle @Override
127    public Collection<SecurityRule> getRules()
128    {
129  125038 return rules;
130    }
131    }
132   
133    /**
134    * Load the rules from wiki documents.
135    *
136    * @param entity Any entity reference that is either a WIKI or a SPACE, or an entity containing a DOCUMENT entity.
137    * @return the access rules that could be loaded into the cache.
138    * @throws org.xwiki.security.authorization.AuthorizationException if an issue arise while reading these rules
139    * from the wiki.
140    */
 
141  2062 toggle @Override
142    public SecurityRuleEntry read(SecurityReference entity) throws AuthorizationException
143    {
144  2060 if (entity == null) {
145  0 return null;
146    }
147   
148  2062 if (entity.getOriginalReference() == null) {
149    // Public users (not logged in) are not stored anywhere and does not have their own rules
150    // More generally, any reference without a valid original reference should not be considered.
151  0 return new InternalSecurityRuleEntry(entity, Collections.<SecurityRule>emptyList());
152    }
153   
154  2061 DocumentReference documentReference;
155  2062 DocumentReference classReference;
156  2062 WikiReference wikiReference;
157   
158  2061 switch (entity.getType()) {
159  151 case WIKI:
160  151 wikiReference = new WikiReference(entity);
161  150 SpaceReference wikiSpace = new SpaceReference(XWikiConstants.XWIKI_SPACE, wikiReference);
162  151 documentReference = new DocumentReference(XWikiConstants.WIKI_DOC, wikiSpace);
163  151 classReference = new DocumentReference(XWikiConstants.GLOBAL_CLASSNAME, wikiSpace);
164  151 break;
165  487 case SPACE:
166  487 wikiReference = new WikiReference(entity.extractReference(EntityType.WIKI));
167  487 documentReference = new DocumentReference(XWikiConstants.SPACE_DOC, new SpaceReference(entity));
168  487 classReference = new DocumentReference(XWikiConstants.GLOBAL_CLASSNAME,
169    new SpaceReference(XWikiConstants.XWIKI_SPACE, wikiReference));
170  487 break;
171  1424 case DOCUMENT:
172  1424 wikiReference = new WikiReference(entity.extractReference(EntityType.WIKI));
173  1424 documentReference = new DocumentReference(entity);
174  1423 classReference = new DocumentReference(XWikiConstants.LOCAL_CLASSNAME,
175    new SpaceReference(XWikiConstants.XWIKI_SPACE, wikiReference));
176  1424 break;
177  0 default:
178  0 throw new EntityTypeNotSupportedException(entity.getType(), this);
179    }
180   
181  2062 return new InternalSecurityRuleEntry(entity,
182    getSecurityRules(documentReference, classReference, wikiReference));
183    }
184   
185    /**
186    * Get the document.
187    * @param documentReference reference to the document to be loaded.
188    * @return a list of matching base objects, or null if none where found.
189    * @throws AuthorizationException if an unexpected error occurs during retrieval.
190    */
 
191  2059 toggle private XWikiDocument getDocument(DocumentReference documentReference) throws AuthorizationException
192    {
193  2060 XWikiContext context = getXWikiContext();
194   
195  2062 try {
196  2061 XWikiDocument doc = context.getWiki().getDocument(documentReference, context);
197  2060 if (doc == null || doc.isNew()) {
198  1137 return null;
199    }
200  924 return doc;
201    } catch (XWikiException e) {
202  0 throw new AuthorizationException(documentReference,
203    "Could not retrieve the document to check security access", e);
204    }
205    }
206   
207    /**
208    * @param wikiReference the wiki to look for owner
209    * @return a reference to the owner of the wiki
210    * @throws AuthorizationException if the owner could not be retrieved.
211    */
 
212  638 toggle private DocumentReference getWikiOwner(WikiReference wikiReference) throws AuthorizationException
213    {
214  638 XWikiContext context = getXWikiContext();
215  638 String wikiOwner;
216  638 try {
217  638 wikiOwner = context.getWiki().getWikiOwner(wikiReference.getName(), context);
218    } catch (XWikiException e) {
219  0 throw new AuthorizationException(wikiReference,
220    "Could not retrieve the owner of this wiki", e);
221    }
222   
223  638 if (wikiOwner == null) {
224  4 return null;
225    }
226   
227  634 return resolver.resolve(wikiOwner, wikiReference);
228    }
229   
230    /**
231    * Read right objects from an XWikiDocument and return them as XWikiSecurityRule.
232    * @param documentReference reference to document to read
233    * @param classReference reference to the right class to read
234    * @param wikiReference reference to the wiki of the document
235    * @return a collection of rules read from the document
236    * @throws AuthorizationException on error reading object from the document
237    */
 
238  2060 toggle private Collection<SecurityRule> getSecurityRules(DocumentReference documentReference,
239    DocumentReference classReference, WikiReference wikiReference) throws AuthorizationException
240    {
241  2060 boolean isGlobalRightsReference = isGlobalRightsReference(documentReference);
242  2062 boolean isGlobalRightRequested = classReference.getName().equals(XWikiConstants.GLOBAL_CLASSNAME);
243  2061 XWikiDocument doc = getDocument(documentReference);
244   
245    // Get implied rules (creator, owner, global rights restriction)
246  2061 List<SecurityRule> securityRules =
247    getImpliedRules(documentReference, doc, isGlobalRightsReference, isGlobalRightRequested);
248   
249  2061 if (doc == null) {
250  1138 return securityRules;
251    }
252   
253    // Convert existing rules on the entity
254  924 List<BaseObject> baseObjects = doc.getXObjects(classReference);
255  924 if (baseObjects != null) {
256  219 for (BaseObject obj : baseObjects) {
257  251 if (obj != null) {
258  243 SecurityRule rule;
259  243 try {
260    // Thanks to the resolver, the users and groups listed by the rights object, inherit
261    // the wiki from the document, unless explicitly given.
262  243 rule = XWikiSecurityRule.createNewRule(obj, resolver, wikiReference,
263    isGlobalRightsReference && !isGlobalRightRequested);
264    } catch (IllegalArgumentException e) {
265    // Do not add badly formed security rules.
266  2 continue;
267    }
268  241 securityRules.add(rule);
269    }
270    }
271    }
272   
273  924 return securityRules;
274    }
275   
276    /**
277    * Get rules implied by wiki owners, document creators, and global rights documents.
278    * @param documentReference reference to the document requested.
279    * @param document the document requested.
280    * @param isGlobalRightsReference true when the document is a document which host global rights.
281    * @param isGlobalRightRequested true when the request concern global rights.
282    * @return a list of implied security rules, or an empty list of there none.
283    * @throws AuthorizationException if anything goes wrong.
284    */
 
285  2061 toggle private List<SecurityRule> getImpliedRules(DocumentReference documentReference, XWikiDocument document,
286    boolean isGlobalRightsReference, boolean isGlobalRightRequested) throws AuthorizationException
287    {
288  2061 List<SecurityRule> rules = new ArrayList<SecurityRule>();
289   
290  2061 if (isGlobalRightsReference) {
291  810 if (isGlobalRightRequested) {
292  638 WikiReference documentWiki = documentReference.getWikiReference();
293  638 DocumentReference owner = getWikiOwner(documentWiki);
294  638 if (owner != null) {
295  634 XWikiContext context = getXWikiContext();
296   
297    // Allow global rights to wiki owner
298  634 if (context.isMainWiki(documentWiki.getName())) {
299  616 rules.add(new XWikiSecurityRule(MAINWIKIOWNER_RIGHTS, RuleState.ALLOW, Collections.singleton(owner), null));
300    } else {
301  18 rules.add(new XWikiSecurityRule(OWNER_RIGHTS, RuleState.ALLOW, Collections.singleton(owner), null));
302    }
303    }
304    } else {
305    // Deny local edit right on documents hosting global rights for anyone but admins.
306  172 rules.add(DENY_EDIT);
307    }
308    }
309   
310  2060 if (!isGlobalRightRequested && document != null) {
311  760 DocumentReference creator = document.getCreatorReference();
312   
313    // Allow local rights to document creator (unless it is a public creator)
314  761 if (creator != null && !XWikiConstants.GUEST_USER.equals(creator.getName())) {
315  750 rules.add(new XWikiSecurityRule(CREATOR_RIGHTS, RuleState.ALLOW, Collections.singleton(creator), null));
316    }
317    }
318   
319  2060 return rules;
320    }
321   
322    /**
323    * Check if the entity reference refers to a document that may contain global rights objects. In other words
324    * '*:XWiki.XWikiPreferences' or '*:*.WebPreferences'.
325    *
326    * @param documentReference the document reference to check.
327    * @return true if the document is scanned for global rights objects during authorization.
328    */
 
329  2062 toggle private boolean isGlobalRightsReference(DocumentReference documentReference) {
330  2062 return (XWikiConstants.SPACE_DOC.equals(documentReference.getName())
331    || (XWikiConstants.WIKI_DOC.equals(documentReference.getName())
332    && XWikiConstants.XWIKI_SPACE.equals(documentReference.getParent().getName())));
333    }
334    }
335