1 16 package org.outerj.daisy.repository.serverimpl.acl; 17 18 import org.outerj.daisy.repository.RepositoryException; 19 import org.outerj.daisy.repository.Document; 20 import org.outerj.daisy.repository.query.QueryException; 21 import org.outerj.daisy.repository.user.Role; 22 import org.outerj.daisy.repository.acl.*; 23 import org.outerj.daisy.repository.commonimpl.acl.AclObjectImpl; 24 import org.outerj.daisy.repository.commonimpl.acl.AclImpl; 25 import org.outerj.daisy.repository.commonimpl.acl.AclStrategy; 26 import org.outerj.daisy.repository.commonimpl.acl.AclEvaluationContext; 27 import org.outerj.daisy.query.model.Tristate; 28 import org.outerj.daisy.query.model.PredicateExpr; 29 30 import java.util.Iterator ; 31 32 37 public class AclEvaluator { 38 private AclStrategy aclStrategy; 39 private AclImpl.IntimateAccess aclInt; 40 private AclEvaluationContext aclEvaluationContext; 41 42 public AclEvaluator(AclImpl acl, AclStrategy aclStrategy, AclEvaluationContext aclEvaluationContext) { 43 this.aclStrategy = aclStrategy; 44 this.aclInt = acl.getIntimateAccess(aclStrategy); 45 this.aclEvaluationContext = aclEvaluationContext; 46 } 47 48 public boolean hasPotentialWriteAccess(long userId, long[] roleIds, long documentTypeId, long collectionId) throws RepositoryException { 49 if (roleIds.length < 1) 50 throw new RepositoryException("Checking of potential write access requires at least one role."); 51 52 try { 53 if (hasRole(roleIds, Role.ADMINISTRATOR)) { 54 return true; 55 } 56 57 boolean[] results = new boolean[roleIds.length]; Iterator objectsIt = aclInt.getObjects().iterator(); 60 while (objectsIt.hasNext()) { 61 AclObjectImpl object = (AclObjectImpl) objectsIt.next(); 62 checkPotentialWriteAccess(object, results, userId, roleIds, documentTypeId, collectionId); 64 } 65 66 for (int i = 0; i < results.length; i++) 68 if (results[i]) 69 return true; 70 return false; 71 } catch (Throwable e) { 72 throw new RepositoryException("Error evaluating ACL.", e); 73 } 74 } 75 76 private void checkPotentialWriteAccess(AclObjectImpl aclObject, boolean[] results, long userId, long[] roleIds, long documentTypeId, long collectionId) throws RepositoryException { 77 AclObjectImpl.IntimateAccess aclObjectInt = aclObject.getIntimateAccess(aclStrategy); 78 assureExpressionCompiled(aclObject, aclObjectInt); 79 Tristate appliesTo; 80 try { 81 PredicateExpr predicateExpr = (PredicateExpr)aclObjectInt.getCompiledExpression(); 82 appliesTo = predicateExpr.appliesTo(new DummyDocForAppliesToTest(documentTypeId, collectionId)); 83 } catch (QueryException e) { 84 throw new RepositoryException("Exception evaluating ACL object expression.", e); 85 } 86 87 if (appliesTo == Tristate.NO) 88 return; 89 90 Iterator entryIt = aclObjectInt.getEntries().iterator(); 93 while (entryIt.hasNext()) { 94 AclEntry entry = (AclEntry)entryIt.next(); 95 96 for (int r = 0; r < roleIds.length; r++) { 97 boolean relevant = false; 98 if (entry.getSubjectType() == AclSubjectType.EVERYONE) { 99 relevant = true; 100 } else if (entry.getSubjectType() == AclSubjectType.ROLE) { 101 if (roleIds[r] == entry.getSubjectValue()) 102 relevant = true; 103 } else if (entry.getSubjectType() == AclSubjectType.USER) { 104 if (userId != -1 && userId == entry.getSubjectValue()) 105 relevant = true; 106 } 107 108 if (relevant) { 109 AclActionType entryAction = entry.get(AclPermission.WRITE); 110 if (entryAction == AclActionType.GRANT) { 112 results[r] = true; 113 } else if (entryAction == AclActionType.DENY && appliesTo == Tristate.YES) { 114 results[r] = false; 115 } 116 } 117 } 118 } 119 } 120 121 public AclResultInfo getAclInfo(long userId, long[] roleIds, Document document) throws RepositoryException { 122 if (roleIds.length < 1) 123 throw new RepositoryException("Evaluation of ACL requires at least one role"); 124 125 try { 126 AclResultInfo result = new AclResultInfo(userId, roleIds, document.getId(), document.getBranchId(), document.getLanguageId()); 127 128 if (hasRole(roleIds, Role.ADMINISTRATOR)) { 129 final String message = "granted because role is Administrator (role id " + Role.ADMINISTRATOR + ")"; 130 for (int i = 0; i < AclPermission.ENUM.length; i++) 131 result.set(AclPermission.ENUM[i], AclActionType.GRANT, message, message); 132 return result; 133 } 134 135 if ((document.isPrivate() && userId == -1) || (document.isPrivate() && userId != -1 && document.getOwner() != userId)) { 136 final String message = "denied because document is marked as private"; 137 for (int i = 0; i < AclPermission.ENUM.length; i++) 138 result.set(AclPermission.ENUM[i], AclActionType.DENY, message, message); 139 return result; 140 } 141 142 for (int i = 0; i < AclPermission.ENUM.length; i++) 143 result.set(AclPermission.ENUM[i], AclActionType.DENY, "denied by default", "denied by default"); 144 145 AclResultInfo[] results = new AclResultInfo[roleIds.length]; 150 for (int i = 0; i < results.length; i++) 151 results[i] = (AclResultInfo)result.clone(); 152 153 Iterator objectsIt = aclInt.getObjects().iterator(); 154 while (objectsIt.hasNext()) { 155 AclObjectImpl object = (AclObjectImpl) objectsIt.next(); 156 completeAclInfo(object, results, userId, roleIds, document); 157 } 158 159 result = merge(results); 160 161 if (!result.isAllowed(AclPermission.READ_LIVE)) { 162 if (result.isAllowed(AclPermission.READ)) { 163 final String message = "cannot have read access if no 'read live' access"; 164 result.set(AclPermission.READ, AclActionType.DENY, message, message); 165 } 166 } 167 168 if (!result.isAllowed(AclPermission.READ) && result.isAllowed(AclPermission.READ_LIVE) && document.isRetired()) { 169 final String message = "cannot read a retired document if only 'read live' access"; 170 result.set(AclPermission.READ_LIVE, AclActionType.DENY, message, message); 171 } 172 173 if (!result.isAllowed(AclPermission.READ_LIVE) || !result.isAllowed(AclPermission.READ)) { 174 if (result.isAllowed(AclPermission.WRITE)) { 175 final String message = "cannot have write access if no read access"; 176 result.set(AclPermission.WRITE, AclActionType.DENY, message, message); 177 } 178 if (result.isAllowed(AclPermission.PUBLISH)) { 179 final String message = "cannot have publish access if no read access"; 180 result.set(AclPermission.PUBLISH, AclActionType.DENY, message, message); 181 } 182 if (result.isAllowed(AclPermission.DELETE)) { 183 final String message = "cannot have delete access if no write access"; 184 result.set(AclPermission.DELETE, AclActionType.DENY, message, message); 185 } 186 } 187 188 if (document.getId() != -1 && userId != -1 && document.getOwner() == userId) { 193 final String message = "granted because user is owner of the document"; 194 result.set(AclPermission.READ_LIVE, AclActionType.GRANT, message, message); 195 result.set(AclPermission.READ, AclActionType.GRANT, message, message); 196 result.set(AclPermission.WRITE, AclActionType.GRANT, message, message); 197 result.set(AclPermission.DELETE, AclActionType.GRANT, message, message); 198 } 201 202 return result; 203 } catch (Throwable e) { 204 throw new RepositoryException("Error evaluating ACL.", e); 205 } 206 } 207 208 private void assureExpressionCompiled(AclObject aclObject, AclObjectImpl.IntimateAccess aclObjectInt) throws RepositoryException { 209 if (aclObjectInt.getCompiledExpression() == null) { 210 Object compiledExpr = aclEvaluationContext.compileObjectExpression(aclObject.getObjectExpr()); 211 aclObjectInt.setCompiledExpression(compiledExpr); 212 } 213 } 214 215 private boolean appliesTo(AclObjectImpl aclObject, AclObjectImpl.IntimateAccess aclObjectInt, Document document) throws RepositoryException { 216 assureExpressionCompiled(aclObject, aclObjectInt); 217 return aclEvaluationContext.checkObjectExpression(aclObjectInt.getCompiledExpression(), document); 218 } 219 220 private void completeAclInfo(AclObjectImpl aclObject, AclResultInfo[] results, long userId, long[] roleIds, Document document) throws RepositoryException { 221 AclObjectImpl.IntimateAccess aclObjectInt = aclObject.getIntimateAccess(aclStrategy); 222 if (appliesTo(aclObject, aclObjectInt, document)) { 225 Iterator entryIt = aclObjectInt.getEntries().iterator(); 226 while (entryIt.hasNext()) { 227 AclEntry entry = (AclEntry)entryIt.next(); 228 229 for (int r = 0; r < roleIds.length; r++) { 230 String subjectReason = null; 231 if (entry.getSubjectType() == AclSubjectType.EVERYONE) { 232 subjectReason = "everyone"; 233 } else if (entry.getSubjectType() == AclSubjectType.ROLE) { 234 if (roleIds[r] == entry.getSubjectValue()) 235 subjectReason = "role is " + entry.getSubjectValue(); 236 } else if (entry.getSubjectType() == AclSubjectType.USER) { 237 if (userId != -1 && userId == entry.getSubjectValue()) 238 subjectReason = "user is " + userId; 239 } 240 241 if (subjectReason != null) { 242 for (int i = 0; i < AclPermission.ENUM.length; i++) { 243 AclActionType entryAction = entry.get(AclPermission.ENUM[i]); 244 if (entryAction != AclActionType.DO_NOTHING) { 245 results[r].set(AclPermission.ENUM[i], entryAction, aclObject.getObjectExpr(), subjectReason); 246 } 247 } 248 } 249 } 250 } 251 } 252 } 253 254 private boolean hasRole(long[] availableRoles, long roleId) { 255 for (int i = 0; i < availableRoles.length; i++) 256 if (availableRoles[i] == roleId) 257 return true; 258 return false; 259 } 260 261 265 private AclResultInfo merge(AclResultInfo[] results) { 266 if (results.length == 1) 267 return results[0]; 268 269 AclResultInfo result = results[0]; 270 271 for (int i = 0; i < AclPermission.ENUM.length; i++) { 272 AclPermission permission = AclPermission.ENUM[i]; 273 if (!result.isAllowed(permission)) { 274 for (int k = 1; k < results.length; k++) { 275 if (results[k].isAllowed(permission)) { 276 result.set(permission, AclActionType.GRANT, results[k].getObjectExpr(permission), results[k].getSubjectReason(permission)); 277 break; 278 } 279 } 280 } 281 } 282 283 return result; 284 } 285 286 } 287 | Popular Tags |