1. Project Clover database Sat Feb 2 2019 06:45:20 CET
  2. Package org.xwiki.security.authorization.internal

File DefaultSecurityEntryReader.java

 

Coverage histogram

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

Code metrics

28
86
11
2
359
210
34
0.4
7.82
5.5
3.09

Classes

Class Line # Actions
DefaultSecurityEntryReader 64 82 0% 31 10
0.9152542491.5%
DefaultSecurityEntryReader.InternalSecurityRuleEntry 101 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.SecurityEntryReaderExtra;
47    import org.xwiki.security.authorization.SecurityRule;
48    import org.xwiki.security.authorization.SecurityRuleEntry;
49    import org.xwiki.security.internal.XWikiConstants;
50   
51    import com.xpn.xwiki.XWikiContext;
52    import com.xpn.xwiki.XWikiException;
53    import com.xpn.xwiki.doc.XWikiDocument;
54    import com.xpn.xwiki.objects.BaseObject;
55   
56    /**
57    * The default implementation of the security rules reader, which reads rules from documents in a wiki.
58    *
59    * @version $Id: 56ebf51c1c239bbe7887c13e168016f5ca6fd869 $
60    * @since 4.0M2
61    */
62    @Component
63    @Singleton
 
64    public class DefaultSecurityEntryReader implements SecurityEntryReader
65    {
66    /** A security rules to deny everyone the edit right by allowing edit to no one. */
67    private static final SecurityRule DENY_EDIT = new AllowEditToNoOneRule();
68   
69    /** Right set allowed for main wiki owner. */
70    private static final Set<Right> MAINWIKIOWNER_RIGHTS = new RightSet(Right.PROGRAM);
71   
72    /** Right set allowed for wiki owner. */
73    private static final Set<Right> OWNER_RIGHTS = new RightSet(Right.ADMIN);
74   
75    /** Right set allowed for document creators. */
76    private static final Set<Right> CREATOR_RIGHTS = new RightSet(Right.CREATOR);
77   
78    /** Resolver for user and group names. */
79    @Inject
80    @Named("user")
81    private DocumentReferenceResolver<String> resolver;
82   
83    /** Execution object. */
84    @Inject
85    private Execution execution;
86   
87    @Inject
88    private List<SecurityEntryReaderExtra> extras;
89   
90    /**
91    * @return the current {@code XWikiContext}
92    */
 
93  24558 toggle private XWikiContext getXWikiContext()
94    {
95  24574 return ((XWikiContext) execution.getContext().getProperty(XWikiContext.EXECUTIONCONTEXT_KEY));
96    }
97   
98    /**
99    * Internal implementation of the SecurityRuleEntry.
100    */
 
101    private final class InternalSecurityRuleEntry extends AbstractSecurityRuleEntry
102    {
103    /** Reference of the related entity. */
104    private final SecurityReference reference;
105   
106    /** The list of objects. */
107    private final Collection<SecurityRule> rules;
108   
109    /**
110    * @param reference reference of the related entity
111    * @param rules collection of security rules applied on the entity.
112    */
 
113  17273 toggle private InternalSecurityRuleEntry(SecurityReference reference, Collection<SecurityRule> rules)
114    {
115  17282 this.reference = reference;
116  17286 this.rules = Collections.unmodifiableCollection(rules);
117    }
118   
119    /**
120    * @return the reference of the related entity
121    */
 
122  497948 toggle @Override
123    public SecurityReference getReference()
124    {
125  497995 return reference;
126    }
127   
128    /**
129    * @return all rules available for this entity
130    */
 
131  2421403 toggle @Override
132    public Collection<SecurityRule> getRules()
133    {
134  2421472 return rules;
135    }
136    }
137   
138    /**
139    * Load the rules from wiki documents.
140    *
141    * @param entity Any entity reference that is either a WIKI or a SPACE, or an entity containing a DOCUMENT entity.
142    * @return the access rules that could be loaded into the cache.
143    * @throws org.xwiki.security.authorization.AuthorizationException if an issue arise while reading these rules from
144    * the wiki.
145    */
 
146  17284 toggle @Override
147    public SecurityRuleEntry read(SecurityReference entity) throws AuthorizationException
148    {
149  17280 if (entity == null) {
150  0 return null;
151    }
152   
153  17285 if (entity.getOriginalReference() == null) {
154    // Public users (not logged in) are not stored anywhere and does not have their own rules
155    // More generally, any reference without a valid original reference should not be considered.
156  0 return new InternalSecurityRuleEntry(entity, Collections.<SecurityRule>emptyList());
157    }
158   
159  17281 DocumentReference documentReference;
160  17288 DocumentReference classReference;
161  17281 WikiReference wikiReference;
162   
163  17289 switch (entity.getType()) {
164  214 case WIKI:
165  214 wikiReference = new WikiReference(entity);
166  214 SpaceReference wikiSpace = new SpaceReference(XWikiConstants.XWIKI_SPACE, wikiReference);
167  214 documentReference = new DocumentReference(XWikiConstants.WIKI_DOC, wikiSpace);
168  214 classReference = new DocumentReference(XWikiConstants.GLOBAL_CLASSNAME, wikiSpace);
169  214 break;
170  3432 case SPACE:
171  3432 wikiReference = new WikiReference(entity.extractReference(EntityType.WIKI));
172  3433 documentReference = new DocumentReference(XWikiConstants.SPACE_DOC, new SpaceReference(entity));
173  3430 classReference = new DocumentReference(XWikiConstants.GLOBAL_CLASSNAME,
174    new SpaceReference(XWikiConstants.XWIKI_SPACE, wikiReference));
175  3433 break;
176  13635 case DOCUMENT:
177  13636 wikiReference = new WikiReference(entity.extractReference(EntityType.WIKI));
178  13640 documentReference = new DocumentReference(entity);
179  13633 classReference = new DocumentReference(XWikiConstants.LOCAL_CLASSNAME,
180    new SpaceReference(XWikiConstants.XWIKI_SPACE, wikiReference));
181  13639 break;
182  0 default:
183  0 throw new EntityTypeNotSupportedException(entity.getType(), this);
184    }
185   
186    // Get standard rules
187  17280 Collection<SecurityRule> rules = getSecurityRules(documentReference, classReference, wikiReference);
188   
189    // Add extras
190  17272 for (SecurityEntryReaderExtra extra : this.extras) {
191  17184 Collection<SecurityRule> extraRules = extra.read(entity);
192  17183 if (extraRules != null) {
193  0 rules.addAll(extraRules);
194    }
195    }
196   
197  17281 return new InternalSecurityRuleEntry(entity, rules);
198    }
199   
200    /**
201    * Get the document.
202    *
203    * @param documentReference reference to the document to be loaded.
204    * @return a list of matching base objects, or null if none where found.
205    * @throws AuthorizationException if an unexpected error occurs during retrieval.
206    */
 
207  17277 toggle private XWikiDocument getDocument(DocumentReference documentReference) throws AuthorizationException
208    {
209  17278 XWikiContext context = getXWikiContext();
210   
211  17286 try {
212  17285 XWikiDocument doc = context.getWiki().getDocument(documentReference, context);
213  17280 if (doc == null || doc.isNew()) {
214  6347 return null;
215    }
216  10943 return doc;
217    } catch (XWikiException e) {
218  0 throw new AuthorizationException(documentReference,
219    "Could not retrieve the document to check security access", e);
220    }
221    }
222   
223    /**
224    * @param wikiReference the wiki to look for owner
225    * @return a reference to the owner of the wiki
226    * @throws AuthorizationException if the owner could not be retrieved.
227    */
 
228  3645 toggle private DocumentReference getWikiOwner(WikiReference wikiReference) throws AuthorizationException
229    {
230  3646 XWikiContext context = getXWikiContext();
231  3647 String wikiOwner;
232  3647 try {
233  3647 wikiOwner = context.getWiki().getWikiOwner(wikiReference.getName(), context);
234    } catch (XWikiException e) {
235  0 throw new AuthorizationException(wikiReference, "Could not retrieve the owner of this wiki", e);
236    }
237   
238  3645 if (wikiOwner == null) {
239  4 return null;
240    }
241   
242  3643 return resolver.resolve(wikiOwner, wikiReference);
243    }
244   
245    /**
246    * Read right objects from an XWikiDocument and return them as XWikiSecurityRule.
247    *
248    * @param documentReference reference to document to read
249    * @param classReference reference to the right class to read
250    * @param wikiReference reference to the wiki of the document
251    * @return a collection of rules read from the document
252    * @throws AuthorizationException on error reading object from the document
253    */
 
254  17275 toggle private Collection<SecurityRule> getSecurityRules(DocumentReference documentReference,
255    DocumentReference classReference, WikiReference wikiReference) throws AuthorizationException
256    {
257  17283 boolean isGlobalRightsReference = isGlobalRightsReference(documentReference);
258  17288 boolean isGlobalRightRequested = classReference.getName().equals(XWikiConstants.GLOBAL_CLASSNAME);
259  17275 XWikiDocument doc = getDocument(documentReference);
260   
261    // Get implied rules (creator, owner, global rights restriction)
262  17278 List<SecurityRule> securityRules =
263    getImpliedRules(documentReference, doc, isGlobalRightsReference, isGlobalRightRequested);
264   
265  17285 if (doc == null) {
266  6345 return securityRules;
267    }
268   
269    // Convert existing rules on the entity
270  10932 List<BaseObject> baseObjects = doc.getXObjects(classReference);
271  10943 if (baseObjects != null) {
272  10899 for (BaseObject obj : baseObjects) {
273  2045 if (obj != null) {
274  1963 SecurityRule rule;
275  1963 try {
276    // Thanks to the resolver, the users and groups listed by the rights object, inherit
277    // the wiki from the document, unless explicitly given.
278  1963 rule = XWikiSecurityRule.createNewRule(obj, resolver, wikiReference,
279    isGlobalRightsReference && !isGlobalRightRequested);
280    } catch (IllegalArgumentException e) {
281    // Do not add badly formed security rules.
282  29 continue;
283    }
284  1934 securityRules.add(rule);
285    }
286    }
287    }
288   
289  10942 return securityRules;
290    }
291   
292    /**
293    * Get rules implied by wiki owners, document creators, and global rights documents.
294    *
295    * @param documentReference reference to the document requested.
296    * @param document the document requested.
297    * @param isGlobalRightsReference true when the document is a document which host global rights.
298    * @param isGlobalRightRequested true when the request concern global rights.
299    * @return a list of implied security rules, or an empty list of there none.
300    * @throws AuthorizationException if anything goes wrong.
301    */
 
302  17280 toggle private List<SecurityRule> getImpliedRules(DocumentReference documentReference, XWikiDocument document,
303    boolean isGlobalRightsReference, boolean isGlobalRightRequested) throws AuthorizationException
304    {
305  17283 List<SecurityRule> rules = new ArrayList<>();
306   
307  17282 if (isGlobalRightsReference) {
308  4925 if (isGlobalRightRequested) {
309  3647 addImpliedGlobalRule(documentReference, rules);
310    } else {
311    // Deny local edit right on documents hosting global rights for anyone but admins.
312  1275 rules.add(DENY_EDIT);
313    }
314    }
315   
316  17279 if (!isGlobalRightRequested && document != null) {
317  10291 DocumentReference creator = document.getCreatorReference();
318   
319    // Allow local rights to document creator (unless it is a public creator)
320  10287 if (creator != null && !XWikiConstants.GUEST_USER.equals(creator.getName())) {
321  10285 rules.add(new XWikiSecurityRule(CREATOR_RIGHTS, RuleState.ALLOW, Collections.singleton(creator), null));
322    }
323    }
324   
325  17277 return rules;
326    }
327   
 
328  3645 toggle private void addImpliedGlobalRule(DocumentReference documentReference, List<SecurityRule> rules)
329    throws AuthorizationException
330    {
331  3646 WikiReference documentWiki = documentReference.getWikiReference();
332  3645 DocumentReference owner = getWikiOwner(documentWiki);
333  3647 if (owner != null) {
334  3640 XWikiContext context = getXWikiContext();
335   
336    // Allow global rights to wiki owner
337  3641 if (context.isMainWiki(documentWiki.getName())) {
338  3622 rules.add(
339    new XWikiSecurityRule(MAINWIKIOWNER_RIGHTS, RuleState.ALLOW, Collections.singleton(owner), null));
340    } else {
341  20 rules.add(new XWikiSecurityRule(OWNER_RIGHTS, RuleState.ALLOW, Collections.singleton(owner), null));
342    }
343    }
344    }
345   
346    /**
347    * Check if the entity reference refers to a document that may contain global rights objects. In other words
348    * '*:XWiki.XWikiPreferences' or '*:*.WebPreferences'.
349    *
350    * @param documentReference the document reference to check.
351    * @return true if the document is scanned for global rights objects during authorization.
352    */
 
353  17273 toggle private boolean isGlobalRightsReference(DocumentReference documentReference)
354    {
355  17279 return (XWikiConstants.SPACE_DOC.equals(documentReference.getName())
356    || (XWikiConstants.WIKI_DOC.equals(documentReference.getName())
357    && XWikiConstants.XWIKI_SPACE.equals(documentReference.getParent().getName())));
358    }
359    }