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

File DefaultAuthorizationManager.java

 

Coverage histogram

../../../../img/srcFileCovDistChart7.png
64% of files have more coverage

Code metrics

44
65
9
1
281
167
43
0.66
7.22
9
4.78

Classes

Class Line # Actions
DefaultAuthorizationManager 46 65 0% 43 35
0.703389870.3%
 

Contributing tests

This file is covered by 32 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;
21   
22    import javax.inject.Inject;
23    import javax.inject.Singleton;
24   
25    import org.apache.commons.lang3.StringUtils;
26    import org.slf4j.Logger;
27    import org.xwiki.component.annotation.Component;
28    import org.xwiki.model.reference.DocumentReference;
29    import org.xwiki.model.reference.EntityReference;
30    import org.xwiki.model.reference.EntityReferenceSerializer;
31    import org.xwiki.security.SecurityReference;
32    import org.xwiki.security.SecurityReferenceFactory;
33    import org.xwiki.security.UserSecurityReference;
34    import org.xwiki.security.authorization.cache.SecurityCache;
35    import org.xwiki.security.authorization.cache.SecurityCacheLoader;
36    import org.xwiki.security.internal.XWikiBridge;
37   
38    /**
39    * Default implementation of the {@link AuthorizationManager}.
40    *
41    * @version $Id: 518bccacbc6ef9ce740b72c9a680deb8bd5975c0 $
42    * @since 4.0M2
43    */
44    @Component
45    @Singleton
 
46    public class DefaultAuthorizationManager implements AuthorizationManager
47    {
48    /** Logger. **/
49    @Inject
50    private Logger logger;
51   
52    /** The cached rights. */
53    @Inject
54    private SecurityCache securityCache;
55   
56    /** The loader for filling the cache. */
57    @Inject
58    private SecurityCacheLoader securityCacheLoader;
59   
60    /** The security reference factory. */
61    @Inject
62    private SecurityReferenceFactory securityReferenceFactory;
63   
64    /** Serializer. */
65    @Inject
66    private EntityReferenceSerializer<String> entityReferenceSerializer;
67   
68    /** XWiki bridge to check for read only wiki. */
69    @Inject
70    private XWikiBridge xwikiBridge;
71   
72    /**
73    * Check if the user is the super admin.
74    *
75    * NOTE: We rely on that the authentication service especially
76    * authenticates user names matching superadmin's in a case
77    * insensitive match, and will ignore any user profile's that may
78    * be matching the superadmin's user name.
79    *
80    * @param user A document reference representing a user identity.
81    * @return {@code true} if and only if the user is determined to be the super user.
82    */
 
83  170269 toggle private boolean isSuperAdmin(DocumentReference user)
84    {
85  170266 return user != null && StringUtils.equalsIgnoreCase(user.getName(), AuthorizationManager.SUPERADMIN_USER);
86    }
87   
 
88  466 toggle @Override
89    public void checkAccess(Right right, DocumentReference userReference, EntityReference entityReference)
90    throws AccessDeniedException
91    {
92  466 try {
93  466 if (!hasSecurityAccess(right, userReference, entityReference, true)) {
94  1 throw new AccessDeniedException(right, userReference, entityReference);
95    }
96    } catch (Exception e) {
97  1 if (e instanceof AccessDeniedException) {
98  1 throw (AccessDeniedException) e;
99    } else {
100  0 throw new AccessDeniedException(right, userReference, entityReference, e);
101    }
102    }
103    }
104   
 
105  169809 toggle @Override
106    public boolean hasAccess(Right right, DocumentReference userReference, EntityReference entityReference)
107    {
108  169805 try {
109  169807 return hasSecurityAccess(right, userReference, entityReference, false);
110    } catch (Exception e) {
111  0 this.logger.error(String.format("Failed to load rights for user [%s] on [%s].",
112  0 (userReference == null) ? AuthorizationException.NULL_USER : userReference,
113  0 (entityReference == null) ? AuthorizationException.NULL_ENTITY : entityReference), e);
114  0 return false;
115    }
116    }
117   
118    /**
119    * Verifies if the user identified by {@code userReference} has the access identified by {@code right} on the
120    * entity identified by {@code entityReference}. Note that some rights may be checked higher in hierarchy of the
121    * provided entity if such right is not enabled at lowest hierarchy level provided.
122    * This function should be used for interface matters, use {@link #checkAccess} at security checkpoints.
123    *
124    * @param right the right to check .
125    * @param userReference the user to check the right for
126    * @param entityReference the entity on which to check the right
127    * @param check if true logging of denied access are made through {@link #logDeny} (at info level), and all
128    * access logging are marked as security checkpoint.
129    * @return {@code true} if the user has the specified right on the entity.
130    * @throws AuthorizationException if an error occurs.
131    */
 
132  170254 toggle private boolean hasSecurityAccess(Right right, DocumentReference userReference, EntityReference entityReference,
133    boolean check)
134    throws AuthorizationException
135    {
136  170262 if (isSuperAdmin(userReference)) {
137  108684 return true;
138    }
139   
140  61576 if (right == null || right == Right.ILLEGAL) {
141  116 if (check) {
142  0 logDeny(userReference, entityReference, right, "no such right");
143    }
144  116 return false;
145    }
146   
147  61459 if ((!right.isReadOnly() && xwikiBridge.isWikiReadOnly())
148    || (userReference == null && xwikiBridge.needsAuthentication(right))) {
149  0 return false;
150    }
151   
152  61460 return evaluateSecurityAccess(right, userReference, entityReference, check);
153    }
154   
 
155  61458 toggle private boolean evaluateSecurityAccess(Right right, DocumentReference userReference,
156    EntityReference entityReference, boolean check)
157    throws AuthorizationException
158    {
159  61458 SecurityAccess securityAccess = getAccess(
160    securityReferenceFactory.newUserReference(userReference),
161    securityReferenceFactory.newEntityReference(entityReference)
162    );
163   
164  61462 RuleState access = securityAccess.get(right);
165  61462 String info = check ? "security checkpoint" : "access inquiry";
166  61462 if (check && access != RuleState.ALLOW) {
167  1 logDeny(userReference, entityReference, right, info);
168    } else {
169  61461 logAccess(access, userReference, entityReference, right, info, true);
170    }
171  61462 return access == RuleState.ALLOW;
172    }
173   
 
174  0 toggle @Override
175    public Right register(RightDescription rightDescription) throws UnableToRegisterRightException
176    {
177  0 try {
178  0 Right newRight = new Right(rightDescription);
179    // cleanup the cache since a new right scheme enter in action
180  0 securityCache.remove(securityReferenceFactory.newEntityReference(xwikiBridge.getMainWikiReference()));
181  0 return newRight;
182    } catch (Throwable e) {
183  0 Right right = Right.toRight(rightDescription.getName());
184  0 if (right != Right.ILLEGAL && right.like(rightDescription)) {
185  0 return right;
186    }
187  0 throw new UnableToRegisterRightException(rightDescription, e);
188    }
189    }
190   
191    /**
192    * Obtain the access for the user on the given entity and load it into the cache if unavailable.
193    *
194    * @param user The user identity.
195    * @param entity The entity. May be of type DOCUMENT, WIKI, or SPACE.
196    * @return the cached access entry.
197    * @exception org.xwiki.security.authorization.AuthorizationException if an error occurs
198    */
 
199  61460 toggle private SecurityAccess getAccess(UserSecurityReference user, SecurityReference entity)
200    throws AuthorizationException
201    {
202  73689 for (SecurityReference ref = entity; ref != null; ref = ref.getParentSecurityReference()) {
203  73688 if (Right.getEnabledRights(ref.getSecurityType()).isEmpty()) {
204    // Skip search on entity types that will obviously have empty/useless list of rules.
205  0 continue;
206    }
207  73690 SecurityRuleEntry entry = securityCache.get(ref);
208  73691 if (entry == null) {
209  1409 SecurityAccess access = securityCacheLoader.load(user, entity).getAccess();
210   
211  1409 this.logger.debug("1. Loaded a new entry for user {} on {} into cache: [{}]", user, entity, access);
212   
213  1409 return access;
214    }
215  72282 if (!entry.isEmpty()) {
216  60053 SecurityAccessEntry accessEntry = securityCache.get(user, ref);
217  60053 if (accessEntry == null) {
218  990 SecurityAccess access = securityCacheLoader.load(user, entity).getAccess();
219   
220  990 logger.debug("2. Loaded a new entry for user {} on {} into cache: [{}]", user, entity, access);
221   
222  990 return access;
223    } else {
224  59063 SecurityAccess access = accessEntry.getAccess();
225   
226  59063 logger.debug("3. Got entry for user {} on {} from cache: [{}]", user, entity, access);
227   
228  59063 return access;
229    }
230    }
231    }
232   
233  0 SecurityAccess access = securityCacheLoader.load(user, entity).getAccess();
234   
235  0 logger.debug("4. Loaded a new default entry for user {} on {} into cache: [{}]", user, entity, access);
236   
237  0 return access;
238    }
239   
240    /**
241    * Log access conclusion.
242    * @param access The ALLOW or DENY state
243    * @param user The user name that was checked.
244    * @param entity The page that was checked.
245    * @param right The action that was requested.
246    * @param info Additional information.
247    * @param debugLevel If true, is made at debug level, else logging is made at info level.
248    */
 
249  61462 toggle private void logAccess(RuleState access, DocumentReference user, EntityReference entity, Right right, String info,
250    boolean debugLevel)
251    {
252  61462 if ((debugLevel && logger.isDebugEnabled()) || (!debugLevel && logger.isInfoEnabled())) {
253  1 String userName = (user != null) ? entityReferenceSerializer.serialize(user)
254    : AuthorizationException.NULL_USER;
255  1 String docName = (entity != null) ? entityReferenceSerializer.serialize(entity)
256    : AuthorizationException.NULL_USER;
257  1 String rightName = (right != null) ? right.getName() : "no right";
258  1 String accessName = (access == RuleState.ALLOW) ? "granted" : "denied";
259  1 String message = "[{}] access has been {} for user [{}] on [{}]: {}";
260  1 if (debugLevel) {
261  0 logger.debug(message, rightName, accessName, userName, docName, info);
262    } else {
263  1 logger.info(message, rightName, accessName, userName, docName, info);
264    }
265    }
266    }
267   
268    /**
269    * Log denied access conclusion.
270    * All denied access conclusion made during a security checkpoint use this method.
271    *
272    * @param user The user name that was checked.
273    * @param entity The page that was checked.
274    * @param right The action that was requested.
275    * @param info Additional information.
276    */
 
277  1 toggle protected void logDeny(DocumentReference user, EntityReference entity, Right right, String info)
278    {
279  1 logAccess(RuleState.DENY, user, entity, right, info, false);
280    }
281    }