1 28 package net.sf.jguard.core.authorization.permissions; 29 30 import java.lang.reflect.Constructor ; 31 import java.lang.reflect.InvocationTargetException ; 32 import java.security.Permission ; 33 import java.security.PermissionCollection ; 34 35 import java.security.Principal ; 36 import java.security.ProtectionDomain ; 37 import java.util.ArrayList ; 38 import java.util.Enumeration ; 39 import java.util.HashMap ; 40 import java.util.HashSet ; 41 import java.util.Iterator ; 42 import java.util.List ; 43 import java.util.Map ; 44 import java.util.Set ; 45 import java.util.logging.Level ; 46 import java.util.logging.Logger ; 47 import java.util.regex.Matcher ; 48 import java.util.regex.Pattern ; 49 50 import net.sf.ehcache.Cache; 51 import net.sf.ehcache.CacheException; 52 import net.sf.ehcache.CacheManager; 53 import net.sf.ehcache.Element; 54 import net.sf.jguard.core.principals.RolePrincipal; 55 import net.sf.jguard.core.principals.UserPrincipal; 56 57 import org.apache.commons.jexl.Expression; 58 import org.apache.commons.jexl.ExpressionFactory; 59 import org.apache.commons.jexl.JexlContext; 60 import org.apache.commons.jexl.JexlHelper; 61 62 63 64 70 public class PermissionUtils { 71 72 private static final Logger logger = Logger.getLogger(PermissionUtils.class.getName()); 73 74 private static CacheManager manager; 75 private static Cache unresolvedPermToNeededExpressions; 76 private static Cache unresolvedPermAndValuesToResolvedPerm; 77 private static boolean cachesEnabled; 78 private static Pattern JEXL_PATTERN = Pattern.compile("(\\$\\{[^\\}]+\\})"); 79 80 89 public static Permission getPermission(String className, String name,String actions) throws ClassNotFoundException { 90 Class clazz = null; 101 try { 102 clazz = Thread.currentThread().getContextClassLoader().loadClass(className); 103 } catch (ClassNotFoundException e1) { 104 logger.log(Level.SEVERE," class "+className+" is not found please check your classPath \n and the permission set in the Datasource \n(either database or JGuardPrincipalsPermissions.xml file) ",e1); 105 throw e1; 106 } 107 Class [] permArgsBasicPermClass = {String .class,String .class}; 108 Class [] permArgsPermClass = {String .class}; 109 Object [] objBasicArray = {name,actions}; 110 Object [] objArray = {name}; 111 Permission newPerm = null; 112 Constructor [] constructors = clazz.getConstructors(); 113 boolean constructorWithActions = false; 114 for(int i = 0;i<constructors.length;i++){ 115 Constructor tempConstructor = constructors[i]; 116 Class [] classes = tempConstructor.getParameterTypes(); 117 if(classes.length==2 && classes[0].equals(String .class)&& classes[1].equals(String .class)){ 118 constructorWithActions = true; 119 break; 120 } 121 } 122 try { 123 if(constructorWithActions == true){ 124 newPerm = (Permission ) clazz.getConstructor(permArgsBasicPermClass).newInstance(objBasicArray); 125 }else{ 126 127 newPerm = (Permission ) clazz.getConstructor(permArgsPermClass).newInstance(objArray); 129 } 130 } catch (IllegalArgumentException e) { 131 logger.log(Level.SEVERE," illegal argument ",e); 132 } catch (SecurityException e) { 133 logger.log(Level.SEVERE,"className="+className); 134 logger.log(Level.SEVERE,"name="+name); 135 logger.log(Level.SEVERE,"actions="+actions); 136 logger.log(Level.SEVERE," you don't have right to instantiate a permission ",e); 137 } catch (InstantiationException e) { 138 logger.log(Level.SEVERE,"className="+className); 139 logger.log(Level.SEVERE,"name="+name); 140 logger.log(Level.SEVERE,"actions="+actions); 141 logger.log(Level.SEVERE," you cannot instantiate a permission ",e); 142 } catch (IllegalAccessException e) { 143 logger.log(Level.SEVERE,"className="+className); 144 logger.log(Level.SEVERE,"name="+name); 145 logger.log(Level.SEVERE,"actions="+actions); 146 } catch (InvocationTargetException e) { 147 logger.log(Level.SEVERE,"className="+className); 148 logger.log(Level.SEVERE,"name="+name); 149 logger.log(Level.SEVERE,"actions="+actions); 150 } catch (NoSuchMethodException e) { 151 logger.log(Level.SEVERE,"method not found =",e); 152 } 153 return newPerm; 154 } 155 156 164 private static boolean evaluateDefinition(String jexlExpression, UserPrincipal userPrincipal) { 165 if(jexlExpression == null) 166 return false; 167 if("true".equalsIgnoreCase(jexlExpression)) 168 return true; 169 if("false".equalsIgnoreCase(jexlExpression)) 170 return false; 171 if(jexlExpression != null && userPrincipal == null) { 172 logger.warning("evaluateDefinition() no UserPrincipal defined, can not use regex definition"); 173 } 174 175 jexlExpression = jexlExpression.substring(2, jexlExpression.length()-1); 176 JexlContext jexlContext = JexlHelper.createContext(); 177 jexlContext.getVars().put("subject.roles", userPrincipal.getRoles()); 178 jexlContext.getVars().put("subject.publicCredentials", userPrincipal.getPublicCredentials()); 179 jexlContext.getVars().put("subject.privateCredentials", userPrincipal.getPrivateCredentials()); 180 181 Object resolvedExpression = null; 182 try { 183 Expression expression = ExpressionFactory.createExpression(jexlExpression); 184 resolvedExpression = expression.evaluate(jexlContext); 185 } catch (Exception e) { 186 logger.warning("Failed to evaluate : " + jexlExpression); 187 } 188 189 if (resolvedExpression == null || !(resolvedExpression instanceof Boolean )){ 190 logger.warning("Subject does not have the required credentials to resolve the role activation : "+ jexlExpression); 191 return false; 192 } else { 193 Boolean val = (Boolean )resolvedExpression; 194 return val.booleanValue(); 195 } 196 } 197 198 209 public static boolean evaluatePrincipal(RolePrincipal ppal, UserPrincipal userPrincipal) { 210 if(!evaluateDefinition(ppal.getDefinition(), userPrincipal)) { 211 if (logger.isLoggable(Level.FINEST)) { 212 logger.finest("evaluatePrincipal() - user's principal definition attr evaluates to false="+ ppal.getLocalName()); 213 } 214 return false; 215 } else if(!ppal.isActive()) { 216 if (logger.isLoggable(Level.FINEST)) { 217 logger.finest("evaluatePrincipal() - user's principal active attr is false="+ ppal.getLocalName()); 218 } 219 return false; 220 } else 221 return true; 222 223 } 224 225 236 public static PermissionCollection evaluatePermissionCollection(ProtectionDomain protectionDomain, PermissionCollection pc){ 237 Principal [] ppals = protectionDomain.getPrincipals(); 239 boolean hasJexlPrincipal = false; 240 int i = 0; 241 242 while (!hasJexlPrincipal && i < ppals.length){ 244 hasJexlPrincipal = ppals[i] instanceof UserPrincipal; 245 i++; 246 } 247 if (!hasJexlPrincipal){ 248 logger.warning("no UserPrincipal defined, can not use regex permissions"); 249 return pc; 250 }else { 251 PermissionCollection resolvedPc = new JGPositivePermissionCollection(); 252 253 UserPrincipal subjectPrincipal = (UserPrincipal)ppals[i-1]; 254 JexlContext jc = JexlHelper.createContext(); 255 Map vars= jc.getVars(); 256 vars.put("subject.roles",subjectPrincipal.getRoles()); 257 vars.put("subject.publicCredentials",subjectPrincipal.getPublicCredentials()); 258 vars.put("subject.privateCredentials",subjectPrincipal.getPrivateCredentials()); 259 260 262 Enumeration permissionsEnum = pc.elements(); 263 264 Map subjectResolvedExpressions = new HashMap (); 265 while (permissionsEnum.hasMoreElements()){ 267 Permission permission = (Permission )permissionsEnum.nextElement(); 268 logger.finest("Resolving permission = " + permission); 269 PermissionCollection pcFromPermission = resolvePermission(permission, subjectResolvedExpressions, jc); 270 Enumeration enumPermissions = pcFromPermission.elements(); 271 while(enumPermissions.hasMoreElements()){ 272 Permission p = (Permission ) enumPermissions.nextElement(); 273 resolvedPc.add(p); 274 } 275 } 276 277 return resolvedPc; 278 } 279 } 280 281 private static HashSet createKey(Permission unresolvedPermission, Map values){ 282 283 HashSet key = new HashSet (); 284 key.add(unresolvedPermission); 285 key.add(values); 286 287 return key; 288 } 289 290 298 private static PermissionCollection resolvePermission (Permission permission, Map subjectResolvedExpressions, JexlContext jexlContext){ 299 300 PermissionCollection resolvedPermissions = new JGPositivePermissionCollection(); 301 302 if (cachesEnabled){ 304 try { 305 Element expressionsCacheEntry = unresolvedPermToNeededExpressions.get(permission); 307 if (expressionsCacheEntry != null){ 308 309 Set neededExpressions =(Set ) expressionsCacheEntry.getValue(); 310 311 if (neededExpressions.isEmpty()){ 312 resolvedPermissions.add(permission); 314 logger.finest("get permission from cache with no resolution needed"); 315 return resolvedPermissions; 316 } 317 318 Iterator itExpressions = neededExpressions.iterator(); 319 Map permissionResolvedExpressions = new HashMap (); 320 boolean hasNull = false; 321 while (itExpressions.hasNext()){ 322 String jexlExpression = (String ) itExpressions.next(); 323 Object resolvedExpression = null; 324 325 if (subjectResolvedExpressions.containsKey(jexlExpression)){ 326 resolvedExpression = subjectResolvedExpressions.get(jexlExpression); 327 permissionResolvedExpressions.put(jexlExpression, resolvedExpression); 328 }else { 329 try { 330 Expression expression = ExpressionFactory.createExpression(jexlExpression); 331 resolvedExpression = expression.evaluate(jexlContext); 332 subjectResolvedExpressions.put(jexlExpression, resolvedExpression); 333 permissionResolvedExpressions.put(jexlExpression, resolvedExpression); 334 } catch (Exception e) { 335 logger.warning("Failed to evaluate : " + jexlExpression); 336 } 337 } 338 339 if (resolvedExpression == null || (resolvedExpression instanceof List && ((List )resolvedExpression).isEmpty())){ 340 hasNull = true; 341 break; 342 } 343 344 } 345 346 if (hasNull){ 347 logger.warning("Subject does not have the required credentials to resolve the permission : "+ permission); 348 resolvedPermissions.add(permission); 350 return resolvedPermissions; 351 } 352 353 HashSet key = createKey(permission, permissionResolvedExpressions); 355 Element permissionCacheEntry = unresolvedPermAndValuesToResolvedPerm.get(key); 356 357 if (permissionCacheEntry != null){ 358 PermissionCollection permissionsFromCache = (PermissionCollection ) permissionCacheEntry.getValue(); 359 logger.finest("get resolved permission from cache"); 360 Enumeration enumeration = permissionsFromCache.elements(); 361 while(enumeration.hasMoreElements()){ 362 Permission permissionFromCache = (Permission ) enumeration.nextElement(); 363 resolvedPermissions.add(permissionFromCache); 364 } 365 return resolvedPermissions; 366 } 367 } 368 } catch (CacheException e) { 369 logger.log(Level.WARNING, "Failed using caches : " + e.getMessage()); 370 } 371 } 372 373 377 List unresolvedPermissions = new ArrayList (); 380 unresolvedPermissions.add(permission); 381 Map resolvedExpressionsByPermission = new HashMap (); 382 383 while (!unresolvedPermissions.isEmpty()) { 384 385 Permission unresolvedPermission = (Permission ) unresolvedPermissions.remove(0); 386 387 String name = unresolvedPermission.getName(); 388 Set partiallyResolvedNames = resolvePartiallyExpression(name, JEXL_PATTERN, jexlContext, resolvedExpressionsByPermission, subjectResolvedExpressions); 389 if(partiallyResolvedNames == null){ 390 return new JGPositivePermissionCollection(); 392 } 393 394 boolean matchesInName = (partiallyResolvedNames.size() != 1 || !partiallyResolvedNames.contains(name)); 395 if (matchesInName) { 396 Iterator itNames = partiallyResolvedNames.iterator(); 397 while (itNames.hasNext()) { 398 String resolvedName = (String ) itNames.next(); 399 Permission partiallyResolvedPermission; 400 try { 401 partiallyResolvedPermission = PermissionUtils.getPermission(permission.getClass().getName(), resolvedName, unresolvedPermission.getActions()); 402 } catch (ClassNotFoundException e) { 403 logger.warning(e.getMessage()); 404 continue; 405 } 406 unresolvedPermissions.add(partiallyResolvedPermission); 407 } 408 continue; 409 } 410 411 String actions = unresolvedPermission.getActions(); 412 String [] actionsArray = actions.split(","); 413 String action = actionsArray[0]; 414 Set partiallyResolvedActions = resolvePartiallyExpression(action, JEXL_PATTERN, jexlContext, resolvedExpressionsByPermission, subjectResolvedExpressions); 415 if(partiallyResolvedActions == null){ 416 return new JGPositivePermissionCollection(); 418 } 419 420 boolean matchesInActions = (partiallyResolvedActions.size() != 1 || !partiallyResolvedActions.contains(action)); 421 if (matchesInActions) { 422 Iterator itActions = partiallyResolvedActions.iterator(); 423 while (itActions.hasNext()) { 424 String resolvedAction = (String ) itActions.next(); 425 Permission partiallyResolvedPermission; 426 try { 427 partiallyResolvedPermission = PermissionUtils.getPermission(permission.getClass().getName(), unresolvedPermission.getName(), resolvedAction); 428 } catch (ClassNotFoundException e) { 429 logger.warning(e.getMessage()); 430 continue; 431 } 432 unresolvedPermissions.add(partiallyResolvedPermission); 433 } 434 continue; 435 } 436 437 resolvedPermissions.add(unresolvedPermission); 440 } 441 442 if (cachesEnabled){ 443 try { 444 List unresolvedKeys = unresolvedPermToNeededExpressions.getKeys(); 446 if (!unresolvedKeys.contains(permission)){ 447 448 HashSet permissionNeededExpressions = new HashSet (resolvedExpressionsByPermission.keySet()); 449 unresolvedPermToNeededExpressions.put(new Element(permission, permissionNeededExpressions)); 450 } 451 } catch (CacheException e) { 452 logger.log(Level.WARNING, "Failed using caches : " + e.getMessage()); 453 } 454 455 Element cacheEntry = new Element(createKey(permission, resolvedExpressionsByPermission), resolvedPermissions); 457 unresolvedPermAndValuesToResolvedPerm.put(cacheEntry); 458 logger.finest("add resolved permissions to cache"); 459 } 460 461 return resolvedPermissions; 462 } 463 464 465 475 private static Set resolvePartiallyExpression (String expression, Pattern pattern, JexlContext jexlContext, Map resolvedExpressionsByPermission, Map subjectResolvedExpressions){ 476 477 boolean hasMatches = false; 478 boolean hasNull = false; 479 480 Set resolvedExpressionsSet = new HashSet (); 481 482 Matcher matcher = pattern.matcher(expression); 483 if (matcher.find()) { 484 hasMatches = true; 485 String matchedExpression = matcher.group(); 486 487 String jexlExpression = matchedExpression.substring (2, matchedExpression.length()-1); 488 Object resolvedExpression = null; 489 490 if (subjectResolvedExpressions.containsKey(jexlExpression)) { 491 resolvedExpression = (Set ) subjectResolvedExpressions.get(jexlExpression); 492 } else { 493 try { 494 Expression expr = ExpressionFactory.createExpression(jexlExpression); 495 resolvedExpression = expr.evaluate(jexlContext); 496 subjectResolvedExpressions.put(jexlExpression, resolvedExpression); 497 498 } catch (Exception e) { 499 logger.warning("Failed to resolve expression : " + jexlExpression); 500 } 501 } 502 503 if ( !(resolvedExpressionsByPermission.containsKey(jexlExpression))){ 504 resolvedExpressionsByPermission.put(jexlExpression, resolvedExpression); 505 } 506 507 if(resolvedExpression == null){ 508 hasNull = true; 510 }else if(resolvedExpression instanceof Set ) { 511 Iterator it = ((Set )resolvedExpression).iterator(); 512 while(it.hasNext()){ 513 StringBuffer builder = new StringBuffer (expression); 514 builder.replace(matcher.start(),matcher.end(),(String )it.next()); 515 resolvedExpressionsSet.add(builder.toString()); 516 } 517 }else if(resolvedExpression instanceof String ){ 518 StringBuffer builder = new StringBuffer (expression); 519 builder.replace(matcher.start(),matcher.end(),(String )resolvedExpression); 520 resolvedExpressionsSet.add(builder.toString()); 521 } 522 } 523 524 if (!hasMatches){ 525 resolvedExpressionsSet.add(expression); 527 } 528 if (hasNull){ 529 return null; 531 } 532 533 return resolvedExpressionsSet; 534 } 535 536 public static void createCaches() throws CacheException{ 537 if(unresolvedPermToNeededExpressions == null || 539 unresolvedPermAndValuesToResolvedPerm == null ){ 540 logger.info("Creating caches for permissions evaluations"); 541 manager = CacheManager.create(); 542 unresolvedPermToNeededExpressions = manager.getCache("unresolvedPermToNeededExpressions"); 543 unresolvedPermAndValuesToResolvedPerm = manager.getCache("unresolvedPermAndValuesToResolvedPerm"); 544 545 if(unresolvedPermToNeededExpressions == null || unresolvedPermAndValuesToResolvedPerm == null){ 546 logger.warning("Failed to create caches for permissions evaluations, use non-caching evaluation"); 547 setCachesEnabled(false); 548 } 549 } 550 } 551 552 public static boolean isCachesEnabled() { 553 return cachesEnabled; 554 } 555 556 public static void setCachesEnabled(boolean cachesEnabled) { 557 PermissionUtils.cachesEnabled = cachesEnabled; 558 } 559 } | Popular Tags |