001 /** 002 * Copyright 2005-2014 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.rice.kim.impl.permission; 017 018 import org.apache.commons.collections.CollectionUtils; 019 import org.apache.commons.lang.StringUtils; 020 import org.apache.commons.lang.exception.ExceptionUtils; 021 import org.apache.log4j.Logger; 022 import org.kuali.rice.core.api.cache.CacheKeyUtils; 023 import org.kuali.rice.core.api.criteria.CriteriaLookupService; 024 import org.kuali.rice.core.api.criteria.GenericQueryResults; 025 import org.kuali.rice.core.api.criteria.LookupCustomizer; 026 import org.kuali.rice.core.api.criteria.QueryByCriteria; 027 import org.kuali.rice.core.api.exception.RiceIllegalArgumentException; 028 import org.kuali.rice.core.api.exception.RiceIllegalStateException; 029 import org.kuali.rice.core.api.membership.MemberType; 030 import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader; 031 import org.kuali.rice.kim.api.KimConstants; 032 import org.kuali.rice.kim.api.common.assignee.Assignee; 033 import org.kuali.rice.kim.api.common.delegate.DelegateType; 034 import org.kuali.rice.kim.api.common.template.Template; 035 import org.kuali.rice.kim.api.common.template.TemplateQueryResults; 036 import org.kuali.rice.kim.api.identity.principal.Principal; 037 import org.kuali.rice.kim.api.permission.Permission; 038 import org.kuali.rice.kim.api.permission.PermissionQueryResults; 039 import org.kuali.rice.kim.api.permission.PermissionService; 040 import org.kuali.rice.kim.api.role.RoleMembership; 041 import org.kuali.rice.kim.api.role.RoleService; 042 import org.kuali.rice.kim.api.services.KimApiServiceLocator; 043 import org.kuali.rice.kim.api.type.KimType; 044 import org.kuali.rice.kim.api.type.KimTypeInfoService; 045 import org.kuali.rice.kim.framework.permission.PermissionTypeService; 046 import org.kuali.rice.kim.impl.common.attribute.AttributeTransform; 047 import org.kuali.rice.kim.impl.common.attribute.KimAttributeDataBo; 048 import org.kuali.rice.kim.impl.role.RolePermissionBo; 049 import org.kuali.rice.krad.service.BusinessObjectService; 050 import org.kuali.rice.krad.util.KRADPropertyConstants; 051 import org.springframework.cache.Cache; 052 import org.springframework.cache.CacheManager; 053 import org.springframework.cache.support.NoOpCacheManager; 054 055 import javax.xml.namespace.QName; 056 import java.util.ArrayList; 057 import java.util.Collection; 058 import java.util.Collections; 059 import java.util.Comparator; 060 import java.util.HashMap; 061 import java.util.List; 062 import java.util.Map; 063 import java.util.concurrent.CopyOnWriteArrayList; 064 065 import static org.kuali.rice.core.api.criteria.PredicateFactory.equal; 066 import static org.kuali.rice.core.api.criteria.PredicateFactory.in; 067 068 public class PermissionServiceImpl implements PermissionService { 069 private static final Logger LOG = Logger.getLogger( PermissionServiceImpl.class ); 070 071 private RoleService roleService; 072 private PermissionTypeService defaultPermissionTypeService; 073 private KimTypeInfoService kimTypeInfoService; 074 private BusinessObjectService businessObjectService; 075 private CriteriaLookupService criteriaLookupService; 076 private CacheManager cacheManager; 077 078 private final CopyOnWriteArrayList<Template> allTemplates = new CopyOnWriteArrayList<Template>(); 079 080 // -------------------- 081 // Authorization Checks 082 // -------------------- 083 084 public PermissionServiceImpl() { 085 this.cacheManager = new NoOpCacheManager(); 086 } 087 088 protected PermissionTypeService getPermissionTypeService(Template permissionTemplate) { 089 if ( permissionTemplate == null ) { 090 throw new IllegalArgumentException( "permissionTemplate may not be null" ); 091 } 092 KimType kimType = kimTypeInfoService.getKimType( permissionTemplate.getKimTypeId() ); 093 String serviceName = kimType.getServiceName(); 094 // if no service specified, return a default implementation 095 if ( StringUtils.isBlank( serviceName ) ) { 096 return defaultPermissionTypeService; 097 } 098 try { 099 Object service = GlobalResourceLoader.getService(QName.valueOf(serviceName)); 100 // if we have a service name, it must exist 101 if ( service == null ) { 102 throw new RuntimeException("null returned for permission type service for service name: " + serviceName); 103 } 104 // whatever we retrieved must be of the correct type 105 if ( !(service instanceof PermissionTypeService) ) { 106 throw new RuntimeException( "Service " + serviceName + " was not a PermissionTypeService. Was: " + service.getClass().getName() ); 107 } 108 return (PermissionTypeService)service; 109 } catch( Exception ex ) { 110 // sometimes service locators throw exceptions rather than returning null, handle that 111 throw new RuntimeException( "Error retrieving service: " + serviceName + " from the KimImplServiceLocator.", ex ); 112 } 113 } 114 115 @Override 116 public boolean hasPermission(String principalId, String namespaceCode, 117 String permissionName) throws RiceIllegalArgumentException { 118 incomingParamCheck(principalId, "principalId"); 119 incomingParamCheck(namespaceCode, "namespaceCode"); 120 incomingParamCheck(permissionName, "permissionName"); 121 122 return isAuthorized( principalId, namespaceCode, permissionName, Collections.<String, String>emptyMap() ); 123 } 124 125 @Override 126 public boolean isAuthorized(String principalId, String namespaceCode, 127 String permissionName, Map<String, String> qualification ) throws RiceIllegalArgumentException { 128 incomingParamCheck(principalId, "principalId"); 129 incomingParamCheck(namespaceCode, "namespaceCode"); 130 incomingParamCheck(permissionName, "permissionName"); 131 incomingParamCheck(qualification, "qualification"); 132 133 if ( LOG.isDebugEnabled() ) { 134 logAuthorizationCheck("Permission", principalId, namespaceCode, permissionName, qualification); 135 } 136 137 List<String> roleIds = getRoleIdsForPermission(namespaceCode, permissionName); 138 if ( roleIds.isEmpty() ) { 139 if ( LOG.isDebugEnabled() ) { 140 LOG.debug( "Result: false"); 141 } 142 return false; 143 } 144 145 boolean isAuthorized = roleService.principalHasRole(principalId, roleIds, qualification); 146 147 if ( LOG.isDebugEnabled() ) { 148 LOG.debug( "Result: " + isAuthorized ); 149 } 150 return isAuthorized; 151 152 } 153 @Override 154 public boolean hasPermissionByTemplate(String principalId, String namespaceCode, String permissionTemplateName, 155 Map<String, String> permissionDetails) throws RiceIllegalArgumentException { 156 incomingParamCheck(principalId, "principalId"); 157 incomingParamCheck(namespaceCode, "namespaceCode"); 158 incomingParamCheck(permissionTemplateName, "permissionTemplateName"); 159 160 return isAuthorizedByTemplate(principalId, namespaceCode, permissionTemplateName, permissionDetails, 161 Collections.<String, String>emptyMap()); 162 } 163 @Override 164 public boolean isAuthorizedByTemplate(String principalId, String namespaceCode, String permissionTemplateName, 165 Map<String, String> permissionDetails, Map<String, String> qualification) throws RiceIllegalArgumentException { 166 incomingParamCheck(principalId, "principalId"); 167 incomingParamCheck(namespaceCode, "namespaceCode"); 168 incomingParamCheck(permissionTemplateName, "permissionTemplateName"); 169 incomingParamCheck(qualification, "qualification"); 170 171 if ( LOG.isDebugEnabled() ) { 172 logAuthorizationCheckByTemplate("Perm Templ", principalId, namespaceCode, permissionTemplateName, permissionDetails, qualification); 173 } 174 175 List<String> roleIds = getRoleIdsForPermissionTemplate(namespaceCode, permissionTemplateName, permissionDetails); 176 if (roleIds.isEmpty()) { 177 if (LOG.isDebugEnabled()) { 178 LOG.debug("Result: false"); 179 } 180 return false; 181 } 182 boolean isAuthorized = roleService.principalHasRole(principalId, roleIds, qualification); 183 if (LOG.isDebugEnabled()) { 184 LOG.debug( "Result: " + isAuthorized ); 185 } 186 return isAuthorized; 187 188 } 189 @Override 190 public List<Permission> getAuthorizedPermissions( String principalId, 191 String namespaceCode, String permissionName, 192 Map<String, String> qualification ) throws RiceIllegalArgumentException { 193 incomingParamCheck(principalId, "principalId"); 194 incomingParamCheck(namespaceCode, "namespaceCode"); 195 incomingParamCheck(permissionName, "permissionName"); 196 incomingParamCheck(qualification, "qualification"); 197 198 // get all the permission objects whose name match that requested 199 List<Permission> permissions = getPermissionsByName(namespaceCode, permissionName); 200 // now, filter the full list by the detail passed 201 List<Permission> applicablePermissions = getMatchingPermissions( permissions, null ); 202 List<Permission> permissionsForUser = getPermissionsForUser(principalId, applicablePermissions, qualification); 203 return permissionsForUser; 204 } 205 @Override 206 public List<Permission> getAuthorizedPermissionsByTemplate(String principalId, String namespaceCode, 207 String permissionTemplateName, Map<String, String> permissionDetails, Map<String, String> qualification) throws RiceIllegalArgumentException { 208 incomingParamCheck(principalId, "principalId"); 209 incomingParamCheck(namespaceCode, "namespaceCode"); 210 incomingParamCheck(permissionTemplateName, "permissionTemplateName"); 211 incomingParamCheck(qualification, "qualification"); 212 213 // get all the permission objects whose name match that requested 214 List<Permission> permissions = getPermissionsByTemplateName(namespaceCode, permissionTemplateName); 215 // now, filter the full list by the detail passed 216 List<Permission> applicablePermissions = getMatchingPermissions( permissions, permissionDetails ); 217 218 return getPermissionsForUser(principalId, applicablePermissions, qualification); 219 } 220 221 /** 222 * Checks the list of permissions against the principal's roles and returns a subset of the list which match. 223 */ 224 protected List<Permission> getPermissionsForUser( String principalId, List<Permission> permissions, 225 Map<String, String> qualification ) { 226 List<Permission> results = new ArrayList<Permission>(); 227 for ( Permission perm : permissions ) { 228 List<String> roleIds = getRoleIdsForPermissions( Collections.singletonList(perm) ); 229 if ( roleIds != null && !roleIds.isEmpty() ) { 230 if ( roleService.principalHasRole( principalId, roleIds, qualification) ) { 231 results.add( perm ); 232 } 233 } 234 } 235 return Collections.unmodifiableList(results); 236 } 237 238 protected Map<String,PermissionTypeService> getPermissionTypeServicesByTemplateId( Collection<Permission> permissions ) { 239 Map<String,PermissionTypeService> permissionTypeServices = new HashMap<String, PermissionTypeService>( permissions.size() ); 240 for (Permission perm : permissions) { 241 if(!permissionTypeServices.containsKey(perm.getTemplate().getId())) { 242 permissionTypeServices.put(perm.getTemplate().getId(), getPermissionTypeService(perm.getTemplate())); 243 } 244 } 245 return permissionTypeServices; 246 } 247 248 protected Map<String,List<Permission>> groupPermissionsByTemplate(Collection<Permission> permissions) { 249 Map<String,List<Permission>> results = new HashMap<String,List<Permission>>(); 250 for (Permission perm : permissions) { 251 List<Permission> perms = results.get(perm.getTemplate().getId()); 252 if (perms == null) { 253 perms = new ArrayList<Permission>(); 254 results.put(perm.getTemplate().getId(), perms); 255 } 256 perms.add(perm); 257 } 258 return results; 259 } 260 261 /** 262 * Compare each of the passed in permissions with the given permissionDetails. Those that 263 * match are added to the result list. 264 */ 265 protected List<Permission> getMatchingPermissions( List<Permission> permissions, Map<String, String> permissionDetails ) { 266 List<String> permissionIds = new ArrayList<String>(permissions.size()); 267 for (Permission permission : permissions) { 268 permissionIds.add(permission.getId()); 269 } 270 String cacheKey = new StringBuilder("{getMatchingPermissions}") 271 .append("permissionIds=").append(CacheKeyUtils.key(permissionIds)).append("|") 272 .append("permissionDetails=").append(CacheKeyUtils.mapKey(permissionDetails)).toString(); 273 Cache.ValueWrapper cachedValue = cacheManager.getCache(Permission.Cache.NAME).get(cacheKey); 274 if (cachedValue != null && cachedValue.get() instanceof List) { 275 return ((List<Permission>)cachedValue.get()); 276 } 277 278 List<Permission> applicablePermissions = new ArrayList<Permission>(); 279 if ( permissionDetails == null || permissionDetails.isEmpty() ) { 280 // if no details passed, assume that all match 281 for ( Permission perm : permissions ) { 282 applicablePermissions.add(perm); 283 } 284 } else { 285 // otherwise, attempt to match the permission details 286 // build a map of the template IDs to the type services 287 Map<String,PermissionTypeService> permissionTypeServices = getPermissionTypeServicesByTemplateId(permissions); 288 // build a map of permissions by template ID 289 Map<String, List<Permission>> permissionMap = groupPermissionsByTemplate(permissions); 290 // loop over the different templates, matching all of the same template against the type 291 // service at once 292 for ( Map.Entry<String,List<Permission>> entry : permissionMap.entrySet() ) { 293 PermissionTypeService permissionTypeService = permissionTypeServices.get( entry.getKey() ); 294 List<Permission> permissionList = entry.getValue(); 295 applicablePermissions.addAll( permissionTypeService.getMatchingPermissions( permissionDetails, permissionList ) ); 296 } 297 } 298 applicablePermissions = Collections.unmodifiableList(applicablePermissions); 299 cacheManager.getCache(Permission.Cache.NAME).put(cacheKey, applicablePermissions); 300 return applicablePermissions; 301 } 302 303 304 @Override 305 public List<Assignee> getPermissionAssignees( String namespaceCode, String permissionName, 306 Map<String, String> qualification ) throws RiceIllegalArgumentException { 307 incomingParamCheck(namespaceCode, "namespaceCode"); 308 incomingParamCheck(permissionName, "permissionName"); 309 incomingParamCheck(qualification, "qualification"); 310 311 List<String> roleIds = getRoleIdsForPermission( namespaceCode, permissionName); 312 if ( roleIds.isEmpty() ) { 313 return Collections.emptyList(); 314 } 315 Collection<RoleMembership> roleMembers = roleService.getRoleMembers( roleIds,qualification ); 316 List<Assignee> results = new ArrayList<Assignee>(); 317 for ( RoleMembership rm : roleMembers ) { 318 List<DelegateType.Builder> delegateBuilderList = new ArrayList<DelegateType.Builder>(); 319 if (!rm.getDelegates().isEmpty()) { 320 for (DelegateType delegate : rm.getDelegates()){ 321 delegateBuilderList.add(DelegateType.Builder.create(delegate)); 322 } 323 } 324 if ( MemberType.PRINCIPAL.equals(rm.getType()) ) { 325 results.add (Assignee.Builder.create(rm.getMemberId(), null, delegateBuilderList).build()); 326 } else if ( MemberType.GROUP.equals(rm.getType()) ) { 327 results.add (Assignee.Builder.create(null, rm.getMemberId(), delegateBuilderList).build()); 328 } 329 } 330 331 return Collections.unmodifiableList(results); 332 } 333 334 @Override 335 public List<Assignee> getPermissionAssigneesByTemplate(String namespaceCode, String permissionTemplateName, 336 Map<String, String> permissionDetails, Map<String, String> qualification) throws RiceIllegalArgumentException { 337 incomingParamCheck(namespaceCode, "namespaceCode"); 338 incomingParamCheck(permissionTemplateName, "permissionTemplateName"); 339 incomingParamCheck(qualification, "qualification"); 340 341 List<String> roleIds = getRoleIdsForPermissionTemplate( namespaceCode, permissionTemplateName, permissionDetails); 342 if ( roleIds.isEmpty() ) { 343 return Collections.emptyList(); 344 } 345 Collection<RoleMembership> roleMembers = roleService.getRoleMembers( roleIds,qualification); 346 List<Assignee> results = new ArrayList<Assignee>(); 347 for ( RoleMembership rm : roleMembers ) { 348 List<DelegateType.Builder> delegateBuilderList = new ArrayList<DelegateType.Builder>(); 349 if (!rm.getDelegates().isEmpty()) { 350 for (DelegateType delegate : rm.getDelegates()){ 351 delegateBuilderList.add(DelegateType.Builder.create(delegate)); 352 } 353 } 354 if ( MemberType.PRINCIPAL.equals(rm.getType()) ) { 355 results.add (Assignee.Builder.create(rm.getMemberId(), null, delegateBuilderList).build()); 356 } else { // a group membership 357 results.add (Assignee.Builder.create(null, rm.getMemberId(), delegateBuilderList).build()); 358 } 359 } 360 return Collections.unmodifiableList(results); 361 } 362 363 @Override 364 public boolean isPermissionDefined( String namespaceCode, String permissionName ) throws RiceIllegalArgumentException { 365 incomingParamCheck(namespaceCode, "namespaceCode"); 366 incomingParamCheck(permissionName, "permissionName"); 367 368 // get all the permission objects whose name match that requested 369 List<Permission> permissions = getPermissionsByName(namespaceCode, permissionName); 370 // now, filter the full list by the detail passed 371 return !getMatchingPermissions(permissions, null).isEmpty(); 372 } 373 374 @Override 375 public boolean isPermissionDefinedByTemplate(String namespaceCode, String permissionTemplateName, 376 Map<String, String> permissionDetails) throws RiceIllegalArgumentException { 377 378 incomingParamCheck(namespaceCode, "namespaceCode"); 379 incomingParamCheck(permissionTemplateName, "permissionTemplateName"); 380 381 // get all the permission objects whose name match that requested 382 List<Permission> permissions = getPermissionsByTemplateName(namespaceCode, permissionTemplateName); 383 // now, filter the full list by the detail passed 384 return !getMatchingPermissions(permissions, permissionDetails).isEmpty(); 385 } 386 387 @Override 388 public List<String> getRoleIdsForPermission(String namespaceCode, String permissionName) throws RiceIllegalArgumentException { 389 incomingParamCheck(namespaceCode, "namespaceCode"); 390 incomingParamCheck(permissionName, "permissionName"); 391 // note...this method is cached at the RoleService interface level using an annotation, but it's called quite 392 // a bit internally, so we'll reproduce the caching here using the same key to help optimize 393 String cacheKey = new StringBuilder("{RoleIds}") 394 .append("namespaceCode=").append(namespaceCode).append("|") 395 .append("name=").append(permissionName).toString(); 396 Cache.ValueWrapper cachedValue = cacheManager.getCache(Permission.Cache.NAME).get(cacheKey); 397 if (cachedValue != null && cachedValue.get() instanceof List) { 398 return ((List<String>)cachedValue.get()); 399 } 400 // get all the permission objects whose name match that requested 401 List<Permission> permissions = getPermissionsByName(namespaceCode, permissionName); 402 // now, filter the full list by the detail passed 403 List<Permission> applicablePermissions = getMatchingPermissions(permissions, null); 404 List<String> roleIds = getRoleIdsForPermissions(applicablePermissions); 405 cacheManager.getCache(Permission.Cache.NAME).put(cacheKey, roleIds); 406 return roleIds; 407 } 408 409 protected List<String> getRoleIdsForPermissionTemplate(String namespaceCode, 410 String permissionTemplateName, 411 Map<String, String> permissionDetails) { 412 String cacheKey = new StringBuilder("{getRoleIdsForPermissionTemplate}") 413 .append("namespaceCode=").append(namespaceCode).append("|") 414 .append("permissionTemplateName=").append(permissionTemplateName).append("|") 415 .append("permissionDetails=").append(CacheKeyUtils.mapKey(permissionDetails)).toString(); 416 Cache.ValueWrapper cachedValue = cacheManager.getCache(Permission.Cache.NAME).get(cacheKey); 417 if (cachedValue != null && cachedValue.get() instanceof List) { 418 return ((List<String>)cachedValue.get()); 419 } 420 // get all the permission objects whose name match that requested 421 List<Permission> permissions = getPermissionsByTemplateName(namespaceCode, permissionTemplateName); 422 // now, filter the full list by the detail passed 423 List<Permission> applicablePermissions = getMatchingPermissions(permissions, permissionDetails); 424 List<String> roleIds = getRoleIdsForPermissions(applicablePermissions); 425 cacheManager.getCache(Permission.Cache.NAME).put(cacheKey, roleIds); 426 return roleIds; 427 } 428 429 // -------------------- 430 // Permission Data 431 // -------------------- 432 433 @Override 434 public Permission getPermission(String permissionId) throws RiceIllegalArgumentException { 435 incomingParamCheck(permissionId, "permissionId"); 436 PermissionBo impl = getPermissionImpl(permissionId); 437 if (impl != null) { 438 return PermissionBo.to(impl); 439 } 440 return null; 441 } 442 443 @Override 444 public List<Permission> findPermissionsByTemplate(String namespaceCode, String permissionTemplateName) throws RiceIllegalArgumentException { 445 incomingParamCheck(namespaceCode, "namespaceCode"); 446 incomingParamCheck(permissionTemplateName, "permissionTemplateName"); 447 448 List<Permission> perms = getPermissionsByTemplateName(namespaceCode, permissionTemplateName); 449 List<Permission> results = new ArrayList<Permission>(perms.size()); 450 for (Permission perm : perms) { 451 results.add(perm); 452 } 453 return Collections.unmodifiableList(results); 454 } 455 456 protected PermissionBo getPermissionImpl(String permissionId) throws RiceIllegalArgumentException { 457 incomingParamCheck(permissionId, "permissionId"); 458 459 HashMap<String,Object> pk = new HashMap<String,Object>( 1 ); 460 pk.put( KimConstants.PrimaryKeyConstants.PERMISSION_ID, permissionId ); 461 return businessObjectService.findByPrimaryKey( PermissionBo.class, pk ); 462 } 463 464 protected List<Permission> getPermissionsByTemplateName( String namespaceCode, String permissionTemplateName ){ 465 String cacheKey = new StringBuilder("{getPermissionsByTemplateName}") 466 .append("namespaceCode=").append(namespaceCode).append("|") 467 .append("permissionTemplateName=").append(permissionTemplateName).toString(); 468 Cache.ValueWrapper cachedValue = cacheManager.getCache(Permission.Cache.NAME).get(cacheKey); 469 if (cachedValue != null && cachedValue.get() instanceof List) { 470 return ((List<Permission>)cachedValue.get()); 471 } 472 HashMap<String,Object> criteria = new HashMap<String,Object>(3); 473 criteria.put("template.namespaceCode", namespaceCode); 474 criteria.put("template.name", permissionTemplateName); 475 criteria.put("template.active", "Y"); 476 criteria.put(KRADPropertyConstants.ACTIVE, "Y"); 477 List<Permission> permissions = 478 toPermissions(businessObjectService.findMatching(PermissionBo.class, criteria)); 479 cacheManager.getCache(Permission.Cache.NAME).put(cacheKey, permissions); 480 return permissions; 481 } 482 483 protected List<Permission> getPermissionsByName( String namespaceCode, String permissionName ) { 484 String cacheKey = new StringBuilder("{getPermissionsByName}") 485 .append("namespaceCode=").append(namespaceCode).append("|") 486 .append("permissionName=").append(permissionName).toString(); 487 Cache.ValueWrapper cachedValue = cacheManager.getCache(Permission.Cache.NAME).get(cacheKey); 488 if (cachedValue != null && cachedValue.get() instanceof List) { 489 return ((List<Permission>)cachedValue.get()); 490 } 491 HashMap<String,Object> criteria = new HashMap<String,Object>(3); 492 criteria.put(KimConstants.UniqueKeyConstants.NAMESPACE_CODE, namespaceCode); 493 criteria.put(KimConstants.UniqueKeyConstants.PERMISSION_NAME, permissionName); 494 criteria.put(KRADPropertyConstants.ACTIVE, "Y"); 495 List<Permission> permissions = 496 toPermissions(businessObjectService.findMatching( PermissionBo.class, criteria )); 497 cacheManager.getCache(Permission.Cache.NAME).put(cacheKey, permissions); 498 return permissions; 499 } 500 501 @Override 502 public Template getPermissionTemplate(String permissionTemplateId) throws RiceIllegalArgumentException { 503 incomingParamCheck(permissionTemplateId, "permissionTemplateId"); 504 505 PermissionTemplateBo impl = businessObjectService.findBySinglePrimaryKey( PermissionTemplateBo.class, permissionTemplateId ); 506 if ( impl != null ) { 507 return PermissionTemplateBo.to(impl); 508 } 509 return null; 510 } 511 512 @Override 513 public Template findPermTemplateByNamespaceCodeAndName(String namespaceCode, 514 String permissionTemplateName) throws RiceIllegalArgumentException { 515 incomingParamCheck(namespaceCode, "namespaceCode"); 516 incomingParamCheck(permissionTemplateName, "permissionTemplateName"); 517 518 Map<String,String> criteria = new HashMap<String,String>(2); 519 criteria.put( KimConstants.UniqueKeyConstants.NAMESPACE_CODE, namespaceCode ); 520 criteria.put( KimConstants.UniqueKeyConstants.PERMISSION_TEMPLATE_NAME, permissionTemplateName ); 521 PermissionTemplateBo impl = businessObjectService.findByPrimaryKey( PermissionTemplateBo.class, criteria ); 522 if ( impl != null ) { 523 return PermissionTemplateBo.to(impl); 524 } 525 return null; 526 } 527 528 @Override 529 public List<Template> getAllTemplates() { 530 if ( allTemplates.isEmpty() ) { 531 Map<String,String> criteria = new HashMap<String,String>(1); 532 criteria.put( KRADPropertyConstants.ACTIVE, "Y" ); 533 List<PermissionTemplateBo> impls = (List<PermissionTemplateBo>) businessObjectService.findMatching( PermissionTemplateBo.class, criteria ); 534 List<Template> infos = new ArrayList<Template>( impls.size() ); 535 for ( PermissionTemplateBo impl : impls ) { 536 infos.add( PermissionTemplateBo.to(impl) ); 537 } 538 Collections.sort(infos, new Comparator<Template>() { 539 @Override public int compare(Template tmpl1, 540 Template tmpl2) { 541 542 int result = tmpl1.getNamespaceCode().compareTo(tmpl2.getNamespaceCode()); 543 if ( result != 0 ) { 544 return result; 545 } 546 result = tmpl1.getName().compareTo(tmpl2.getName()); 547 return result; 548 } 549 }); 550 allTemplates.addAll(infos); 551 } 552 return Collections.unmodifiableList(allTemplates); 553 } 554 555 556 @Override 557 public Permission createPermission(Permission permission) 558 throws RiceIllegalArgumentException, RiceIllegalStateException { 559 incomingParamCheck(permission, "permission"); 560 561 if (StringUtils.isNotBlank(permission.getId()) && getPermission(permission.getId()) != null) { 562 throw new RiceIllegalStateException("the permission to create already exists: " + permission); 563 } 564 List<PermissionAttributeBo> attrBos = Collections.emptyList(); 565 if (permission.getTemplate() != null) { 566 attrBos = KimAttributeDataBo.createFrom(PermissionAttributeBo.class, permission.getAttributes(), permission.getTemplate().getKimTypeId()); 567 } 568 PermissionBo bo = PermissionBo.from(permission); 569 if (bo.getTemplate() == null && bo.getTemplateId() != null) { 570 bo.setTemplate(PermissionTemplateBo.from(getPermissionTemplate(bo.getTemplateId()))); 571 } 572 bo.setAttributeDetails(attrBos); 573 return PermissionBo.to(businessObjectService.save(bo)); 574 } 575 576 @Override 577 public Permission updatePermission(Permission permission) 578 throws RiceIllegalArgumentException, RiceIllegalStateException { 579 incomingParamCheck(permission, "permission"); 580 581 PermissionBo oldPermission = getPermissionImpl(permission.getId()); 582 if (StringUtils.isBlank(permission.getId()) || oldPermission == null) { 583 throw new RiceIllegalStateException("the permission does not exist: " + permission); 584 } 585 586 //List<PermissionAttributeBo> attrBos = KimAttributeDataBo.createFrom(PermissionAttributeBo.class, permission.getAttributes(), permission.getTemplate().getKimTypeId()); 587 588 List<PermissionAttributeBo> oldAttrBos = oldPermission.getAttributeDetails(); 589 //put old attributes in map for easier updating 590 Map<String, PermissionAttributeBo> oldAttrMap = new HashMap<String, PermissionAttributeBo>(); 591 for (PermissionAttributeBo oldAttr : oldAttrBos) { 592 oldAttrMap.put(oldAttr.getKimAttribute().getAttributeName(), oldAttr); 593 } 594 List<PermissionAttributeBo> newAttrBos = new ArrayList<PermissionAttributeBo>(); 595 for (String key : permission.getAttributes().keySet()) { 596 if (oldAttrMap.containsKey(key)) { 597 PermissionAttributeBo updatedAttr = oldAttrMap.get(key); 598 updatedAttr.setAttributeValue(permission.getAttributes().get(key)); 599 newAttrBos.add(updatedAttr); 600 } else { //new attribute 601 newAttrBos.addAll(KimAttributeDataBo.createFrom(PermissionAttributeBo.class, Collections.singletonMap(key, permission.getAttributes().get(key)), permission.getTemplate().getKimTypeId())); 602 } 603 } 604 PermissionBo bo = PermissionBo.from(permission); 605 if (CollectionUtils.isNotEmpty(newAttrBos)) { 606 if(null!= bo.getAttributeDetails()) { 607 bo.getAttributeDetails().clear(); 608 } 609 bo.setAttributeDetails(newAttrBos); 610 } 611 if (bo.getTemplate() == null && bo.getTemplateId() != null) { 612 bo.setTemplate(PermissionTemplateBo.from(getPermissionTemplate(bo.getTemplateId()))); 613 } 614 615 return PermissionBo.to(businessObjectService.save(bo)); 616 } 617 618 @Override 619 public Permission findPermByNamespaceCodeAndName(String namespaceCode, String permissionName) 620 throws RiceIllegalArgumentException { 621 incomingParamCheck(namespaceCode, "namespaceCode"); 622 incomingParamCheck(permissionName, "permissionName"); 623 624 PermissionBo permissionBo = getPermissionBoByName(namespaceCode, permissionName); 625 if (permissionBo != null) { 626 return PermissionBo.to(permissionBo); 627 } 628 return null; 629 } 630 631 protected PermissionBo getPermissionBoByName(String namespaceCode, String permissionName) { 632 if (StringUtils.isBlank(namespaceCode) 633 || StringUtils.isBlank(permissionName)) { 634 return null; 635 } 636 Map<String, String> criteria = new HashMap<String, String>(); 637 criteria.put(KimConstants.UniqueKeyConstants.NAMESPACE_CODE, namespaceCode); 638 criteria.put(KimConstants.UniqueKeyConstants.NAME, permissionName); 639 criteria.put(KRADPropertyConstants.ACTIVE, "Y"); 640 // while this is not actually the primary key - there will be at most one row with these criteria 641 return businessObjectService.findByPrimaryKey(PermissionBo.class, criteria); 642 } 643 644 @Override 645 public PermissionQueryResults findPermissions(final QueryByCriteria queryByCriteria) 646 throws RiceIllegalArgumentException { 647 incomingParamCheck(queryByCriteria, "queryByCriteria"); 648 649 LookupCustomizer.Builder<PermissionBo> lc = LookupCustomizer.Builder.create(); 650 lc.setPredicateTransform(AttributeTransform.getInstance()); 651 652 GenericQueryResults<PermissionBo> results = criteriaLookupService.lookup(PermissionBo.class, queryByCriteria, lc.build()); 653 654 PermissionQueryResults.Builder builder = PermissionQueryResults.Builder.create(); 655 builder.setMoreResultsAvailable(results.isMoreResultsAvailable()); 656 builder.setTotalRowCount(results.getTotalRowCount()); 657 658 final List<Permission.Builder> ims = new ArrayList<Permission.Builder>(); 659 for (PermissionBo bo : results.getResults()) { 660 ims.add(Permission.Builder.create(bo)); 661 } 662 663 builder.setResults(ims); 664 return builder.build(); 665 } 666 667 @Override 668 public TemplateQueryResults findPermissionTemplates(final QueryByCriteria queryByCriteria) 669 throws RiceIllegalArgumentException { 670 incomingParamCheck(queryByCriteria, "queryByCriteria"); 671 672 GenericQueryResults<PermissionTemplateBo> results = criteriaLookupService.lookup(PermissionTemplateBo.class, queryByCriteria); 673 674 TemplateQueryResults.Builder builder = TemplateQueryResults.Builder.create(); 675 builder.setMoreResultsAvailable(results.isMoreResultsAvailable()); 676 builder.setTotalRowCount(results.getTotalRowCount()); 677 678 final List<Template.Builder> ims = new ArrayList<Template.Builder>(); 679 for (PermissionTemplateBo bo : results.getResults()) { 680 ims.add(Template.Builder.create(bo)); 681 } 682 683 builder.setResults(ims); 684 return builder.build(); 685 } 686 687 private List<String> getRoleIdsForPermissions( Collection<Permission> permissions ) { 688 if (CollectionUtils.isEmpty(permissions)) { 689 return Collections.emptyList(); 690 } 691 List<String> ids = new ArrayList<String>(); 692 for (Permission p : permissions) { 693 ids.add(p.getId()); 694 } 695 696 return getRoleIdsForPermissionIds(ids); 697 } 698 699 private List<String> getRoleIdsForPermissionIds(Collection<String> permissionIds) { 700 if (CollectionUtils.isEmpty(permissionIds)) { 701 return Collections.emptyList(); 702 } 703 String cacheKey = new StringBuilder("{getRoleIdsForPermissionIds}") 704 .append("permissionIds=").append(CacheKeyUtils.key(permissionIds)).toString(); 705 Cache.ValueWrapper cachedValue = cacheManager.getCache(Permission.Cache.NAME).get(cacheKey); 706 if (cachedValue != null && cachedValue.get() instanceof List) { 707 return ((List<String>)cachedValue.get()); 708 } 709 QueryByCriteria query = QueryByCriteria.Builder.fromPredicates(equal("active", "true"), in("permissionId", permissionIds.toArray(new String[]{}))); 710 GenericQueryResults<RolePermissionBo> results = criteriaLookupService.lookup(RolePermissionBo.class, query); 711 List<String> roleIds = new ArrayList<String>(); 712 for (RolePermissionBo bo : results.getResults()) { 713 roleIds.add(bo.getRoleId()); 714 } 715 roleIds = Collections.unmodifiableList(roleIds); 716 cacheManager.getCache(Permission.Cache.NAME).put(cacheKey, roleIds); 717 return roleIds; 718 } 719 720 /** 721 * Sets the kimTypeInfoService attribute value. 722 * 723 * @param kimTypeInfoService The kimTypeInfoService to set. 724 */ 725 public void setKimTypeInfoService(KimTypeInfoService kimTypeInfoService) { 726 this.kimTypeInfoService = kimTypeInfoService; 727 } 728 729 /** 730 * Sets the defaultPermissionTypeService attribute value. 731 * 732 * @param defaultPermissionTypeService The defaultPermissionTypeService to set. 733 */ 734 public void setDefaultPermissionTypeService(PermissionTypeService defaultPermissionTypeService) { 735 this.defaultPermissionTypeService = defaultPermissionTypeService; 736 } 737 738 /** 739 * Sets the roleService attribute value. 740 * 741 * @param roleService The roleService to set. 742 */ 743 public void setRoleService(RoleService roleService) { 744 this.roleService = roleService; 745 } 746 747 /** 748 * Sets the businessObjectService attribute value. 749 * 750 * @param businessObjectService The businessObjectService to set. 751 */ 752 public void setBusinessObjectService(final BusinessObjectService businessObjectService) { 753 this.businessObjectService = businessObjectService; 754 } 755 756 /** 757 * Sets the criteriaLookupService attribute value. 758 * 759 * @param criteriaLookupService The criteriaLookupService to set. 760 */ 761 public void setCriteriaLookupService(final CriteriaLookupService criteriaLookupService) { 762 this.criteriaLookupService = criteriaLookupService; 763 } 764 765 /** 766 * Sets the cache manager which this service implementation can for internal caching. 767 * Calling this setter is optional, though the value passed to it must not be null. 768 * 769 * @param cacheManager the cache manager to use for internal caching, must not be null 770 * @throws IllegalArgumentException if a null cache manager is passed 771 */ 772 public void setCacheManager(final CacheManager cacheManager) { 773 if (cacheManager == null) { 774 throw new IllegalArgumentException("cacheManager must not be null"); 775 } 776 this.cacheManager = cacheManager; 777 } 778 779 private List<Permission> toPermissions(Collection<PermissionBo> permissionBos) { 780 if (CollectionUtils.isEmpty(permissionBos)) { 781 return new ArrayList<Permission>(); 782 } 783 List<Permission> permissions = new ArrayList<Permission>(permissionBos.size()); 784 for (PermissionBo permissionBo : permissionBos) { 785 permissions.add(PermissionBo.to(permissionBo)); 786 } 787 return permissions; 788 } 789 790 protected void logAuthorizationCheck(String checkType, String principalId, String namespaceCode, String permissionName, Map<String, String> qualification ) { 791 StringBuilder sb = new StringBuilder(); 792 sb.append( '\n' ); 793 sb.append( "Is AuthZ for " ).append( checkType ).append( ": " ).append( namespaceCode ).append( "/" ).append( permissionName ).append( '\n' ); 794 sb.append( " Principal: " ).append( principalId ); 795 if ( principalId != null ) { 796 Principal principal = KimApiServiceLocator.getIdentityService().getPrincipal(principalId); 797 if ( principal != null ) { 798 sb.append( " (" ).append( principal.getPrincipalName() ).append( ')' ); 799 } 800 } 801 sb.append( '\n' ); 802 sb.append( " Qualifiers:\n" ); 803 if ( qualification != null && !qualification.isEmpty() ) { 804 sb.append( qualification ); 805 } else { 806 sb.append( " [null]\n" ); 807 } 808 if (LOG.isTraceEnabled()) { 809 LOG.trace( sb.append(ExceptionUtils.getStackTrace(new Throwable()))); 810 } else { 811 LOG.debug(sb.toString()); 812 } 813 } 814 815 protected void logAuthorizationCheckByTemplate(String checkType, String principalId, String namespaceCode, String permissionName, 816 Map<String, String> permissionDetails, Map<String, String> qualification ) { 817 StringBuilder sb = new StringBuilder(); 818 sb.append( '\n' ); 819 sb.append( "Is AuthZ for " ).append( checkType ).append( ": " ).append( namespaceCode ).append( "/" ).append( permissionName ).append( '\n' ); 820 sb.append( " Principal: " ).append( principalId ); 821 if ( principalId != null ) { 822 Principal principal = KimApiServiceLocator.getIdentityService().getPrincipal(principalId); 823 if ( principal != null ) { 824 sb.append( " (" ).append( principal.getPrincipalName() ).append( ')' ); 825 } 826 } 827 sb.append( '\n' ); 828 sb.append( " Details:\n" ); 829 if ( permissionDetails != null ) { 830 sb.append( permissionDetails ); 831 } else { 832 sb.append( " [null]\n" ); 833 } 834 sb.append( " Qualifiers:\n" ); 835 if ( qualification != null && !qualification.isEmpty() ) { 836 sb.append( qualification ); 837 } else { 838 sb.append( " [null]\n" ); 839 } 840 if (LOG.isTraceEnabled()) { 841 LOG.trace( sb.append(ExceptionUtils.getStackTrace(new Throwable()))); 842 } else { 843 LOG.debug(sb.toString()); 844 } 845 } 846 847 private void incomingParamCheck(Object object, String name) { 848 if (object == null) { 849 throw new RiceIllegalArgumentException(name + " was null"); 850 } else if (object instanceof String 851 && StringUtils.isBlank((String) object)) { 852 throw new RiceIllegalArgumentException(name + " was blank"); 853 } 854 } 855 856 857 }