001/** 002 * Copyright 2005-2016 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 */ 016package org.kuali.rice.kim.impl.permission; 017 018import org.apache.commons.collections.CollectionUtils; 019import org.apache.commons.lang.StringUtils; 020import org.apache.commons.lang.exception.ExceptionUtils; 021import org.apache.log4j.Logger; 022import org.kuali.rice.core.api.cache.CacheKeyUtils; 023import org.kuali.rice.core.api.criteria.CriteriaLookupService; 024import org.kuali.rice.core.api.criteria.GenericQueryResults; 025import org.kuali.rice.core.api.criteria.LookupCustomizer; 026import org.kuali.rice.core.api.criteria.QueryByCriteria; 027import org.kuali.rice.core.api.exception.RiceIllegalArgumentException; 028import org.kuali.rice.core.api.exception.RiceIllegalStateException; 029import org.kuali.rice.core.api.membership.MemberType; 030import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader; 031import org.kuali.rice.kim.api.KimConstants; 032import org.kuali.rice.kim.api.common.assignee.Assignee; 033import org.kuali.rice.kim.api.common.delegate.DelegateType; 034import org.kuali.rice.kim.api.common.template.Template; 035import org.kuali.rice.kim.api.common.template.TemplateQueryResults; 036import org.kuali.rice.kim.api.identity.principal.Principal; 037import org.kuali.rice.kim.api.permission.Permission; 038import org.kuali.rice.kim.api.permission.PermissionQueryResults; 039import org.kuali.rice.kim.api.permission.PermissionService; 040import org.kuali.rice.kim.api.role.RoleMembership; 041import org.kuali.rice.kim.api.role.RoleService; 042import org.kuali.rice.kim.api.services.KimApiServiceLocator; 043import org.kuali.rice.kim.api.type.KimType; 044import org.kuali.rice.kim.api.type.KimTypeInfoService; 045import org.kuali.rice.kim.framework.permission.PermissionTypeService; 046import org.kuali.rice.kim.impl.common.attribute.AttributeTransform; 047import org.kuali.rice.kim.impl.common.attribute.KimAttributeDataBo; 048import org.kuali.rice.kim.impl.role.RolePermissionBo; 049import org.kuali.rice.krad.service.BusinessObjectService; 050import org.kuali.rice.krad.util.KRADPropertyConstants; 051import org.springframework.cache.Cache; 052import org.springframework.cache.CacheManager; 053import org.springframework.cache.support.NoOpCacheManager; 054 055import javax.xml.namespace.QName; 056import java.util.ArrayList; 057import java.util.Collection; 058import java.util.Collections; 059import java.util.Comparator; 060import java.util.HashMap; 061import java.util.List; 062import java.util.Map; 063import java.util.concurrent.CopyOnWriteArrayList; 064 065import static org.kuali.rice.core.api.criteria.PredicateFactory.equal; 066import static org.kuali.rice.core.api.criteria.PredicateFactory.in; 067 068public 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(KRADPropertyConstants.ACTIVE, "Y"); 476 List<Permission> permissions = 477 toPermissions(businessObjectService.findMatching(PermissionBo.class, criteria)); 478 cacheManager.getCache(Permission.Cache.NAME).put(cacheKey, permissions); 479 return permissions; 480 } 481 482 protected List<Permission> getPermissionsByName( String namespaceCode, String permissionName ) { 483 String cacheKey = new StringBuilder("{getPermissionsByName}") 484 .append("namespaceCode=").append(namespaceCode).append("|") 485 .append("permissionName=").append(permissionName).toString(); 486 Cache.ValueWrapper cachedValue = cacheManager.getCache(Permission.Cache.NAME).get(cacheKey); 487 if (cachedValue != null && cachedValue.get() instanceof List) { 488 return ((List<Permission>)cachedValue.get()); 489 } 490 HashMap<String,Object> criteria = new HashMap<String,Object>(3); 491 criteria.put(KimConstants.UniqueKeyConstants.NAMESPACE_CODE, namespaceCode); 492 criteria.put(KimConstants.UniqueKeyConstants.PERMISSION_NAME, permissionName); 493 criteria.put(KRADPropertyConstants.ACTIVE, "Y"); 494 List<Permission> permissions = 495 toPermissions(businessObjectService.findMatching( PermissionBo.class, criteria )); 496 cacheManager.getCache(Permission.Cache.NAME).put(cacheKey, permissions); 497 return permissions; 498 } 499 500 @Override 501 public Template getPermissionTemplate(String permissionTemplateId) throws RiceIllegalArgumentException { 502 incomingParamCheck(permissionTemplateId, "permissionTemplateId"); 503 504 PermissionTemplateBo impl = businessObjectService.findBySinglePrimaryKey( PermissionTemplateBo.class, permissionTemplateId ); 505 if ( impl != null ) { 506 return PermissionTemplateBo.to(impl); 507 } 508 return null; 509 } 510 511 @Override 512 public Template findPermTemplateByNamespaceCodeAndName(String namespaceCode, 513 String permissionTemplateName) throws RiceIllegalArgumentException { 514 incomingParamCheck(namespaceCode, "namespaceCode"); 515 incomingParamCheck(permissionTemplateName, "permissionTemplateName"); 516 517 Map<String,String> criteria = new HashMap<String,String>(2); 518 criteria.put( KimConstants.UniqueKeyConstants.NAMESPACE_CODE, namespaceCode ); 519 criteria.put( KimConstants.UniqueKeyConstants.PERMISSION_TEMPLATE_NAME, permissionTemplateName ); 520 PermissionTemplateBo impl = businessObjectService.findByPrimaryKey( PermissionTemplateBo.class, criteria ); 521 if ( impl != null ) { 522 return PermissionTemplateBo.to(impl); 523 } 524 return null; 525 } 526 527 @Override 528 public List<Template> getAllTemplates() { 529 if ( allTemplates.isEmpty() ) { 530 Map<String,String> criteria = new HashMap<String,String>(1); 531 criteria.put( KRADPropertyConstants.ACTIVE, "Y" ); 532 List<PermissionTemplateBo> impls = (List<PermissionTemplateBo>) businessObjectService.findMatching( PermissionTemplateBo.class, criteria ); 533 List<Template> infos = new ArrayList<Template>( impls.size() ); 534 for ( PermissionTemplateBo impl : impls ) { 535 infos.add( PermissionTemplateBo.to(impl) ); 536 } 537 Collections.sort(infos, new Comparator<Template>() { 538 @Override public int compare(Template tmpl1, 539 Template tmpl2) { 540 541 int result = tmpl1.getNamespaceCode().compareTo(tmpl2.getNamespaceCode()); 542 if ( result != 0 ) { 543 return result; 544 } 545 result = tmpl1.getName().compareTo(tmpl2.getName()); 546 return result; 547 } 548 }); 549 allTemplates.addAll(infos); 550 } 551 return Collections.unmodifiableList(allTemplates); 552 } 553 554 555 @Override 556 public Permission createPermission(Permission permission) 557 throws RiceIllegalArgumentException, RiceIllegalStateException { 558 incomingParamCheck(permission, "permission"); 559 560 if (StringUtils.isNotBlank(permission.getId()) && getPermission(permission.getId()) != null) { 561 throw new RiceIllegalStateException("the permission to create already exists: " + permission); 562 } 563 List<PermissionAttributeBo> attrBos = Collections.emptyList(); 564 if (permission.getTemplate() != null) { 565 attrBos = KimAttributeDataBo.createFrom(PermissionAttributeBo.class, permission.getAttributes(), permission.getTemplate().getKimTypeId()); 566 } 567 PermissionBo bo = PermissionBo.from(permission); 568 if (bo.getTemplate() == null && bo.getTemplateId() != null) { 569 bo.setTemplate(PermissionTemplateBo.from(getPermissionTemplate(bo.getTemplateId()))); 570 } 571 bo.setAttributeDetails(attrBos); 572 return PermissionBo.to(businessObjectService.save(bo)); 573 } 574 575 @Override 576 public Permission updatePermission(Permission permission) 577 throws RiceIllegalArgumentException, RiceIllegalStateException { 578 incomingParamCheck(permission, "permission"); 579 580 PermissionBo oldPermission = getPermissionImpl(permission.getId()); 581 if (StringUtils.isBlank(permission.getId()) || oldPermission == null) { 582 throw new RiceIllegalStateException("the permission does not exist: " + permission); 583 } 584 585 //List<PermissionAttributeBo> attrBos = KimAttributeDataBo.createFrom(PermissionAttributeBo.class, permission.getAttributes(), permission.getTemplate().getKimTypeId()); 586 587 List<PermissionAttributeBo> oldAttrBos = oldPermission.getAttributeDetails(); 588 //put old attributes in map for easier updating 589 Map<String, PermissionAttributeBo> oldAttrMap = new HashMap<String, PermissionAttributeBo>(); 590 for (PermissionAttributeBo oldAttr : oldAttrBos) { 591 oldAttrMap.put(oldAttr.getKimAttribute().getAttributeName(), oldAttr); 592 } 593 List<PermissionAttributeBo> newAttrBos = new ArrayList<PermissionAttributeBo>(); 594 for (String key : permission.getAttributes().keySet()) { 595 if (oldAttrMap.containsKey(key)) { 596 PermissionAttributeBo updatedAttr = oldAttrMap.get(key); 597 updatedAttr.setAttributeValue(permission.getAttributes().get(key)); 598 newAttrBos.add(updatedAttr); 599 } else { //new attribute 600 newAttrBos.addAll(KimAttributeDataBo.createFrom(PermissionAttributeBo.class, Collections.singletonMap(key, permission.getAttributes().get(key)), permission.getTemplate().getKimTypeId())); 601 } 602 } 603 PermissionBo bo = PermissionBo.from(permission); 604 if (CollectionUtils.isNotEmpty(newAttrBos)) { 605 if(null!= bo.getAttributeDetails()) { 606 bo.getAttributeDetails().clear(); 607 } 608 bo.setAttributeDetails(newAttrBos); 609 } 610 if (bo.getTemplate() == null && bo.getTemplateId() != null) { 611 bo.setTemplate(PermissionTemplateBo.from(getPermissionTemplate(bo.getTemplateId()))); 612 } 613 614 return PermissionBo.to(businessObjectService.save(bo)); 615 } 616 617 @Override 618 public Permission findPermByNamespaceCodeAndName(String namespaceCode, String permissionName) 619 throws RiceIllegalArgumentException { 620 incomingParamCheck(namespaceCode, "namespaceCode"); 621 incomingParamCheck(permissionName, "permissionName"); 622 623 PermissionBo permissionBo = getPermissionBoByName(namespaceCode, permissionName); 624 if (permissionBo != null) { 625 return PermissionBo.to(permissionBo); 626 } 627 return null; 628 } 629 630 protected PermissionBo getPermissionBoByName(String namespaceCode, String permissionName) { 631 if (StringUtils.isBlank(namespaceCode) 632 || StringUtils.isBlank(permissionName)) { 633 return null; 634 } 635 Map<String, String> criteria = new HashMap<String, String>(); 636 criteria.put(KimConstants.UniqueKeyConstants.NAMESPACE_CODE, namespaceCode); 637 criteria.put(KimConstants.UniqueKeyConstants.NAME, permissionName); 638 criteria.put(KRADPropertyConstants.ACTIVE, "Y"); 639 // while this is not actually the primary key - there will be at most one row with these criteria 640 return businessObjectService.findByPrimaryKey(PermissionBo.class, criteria); 641 } 642 643 @Override 644 public PermissionQueryResults findPermissions(final QueryByCriteria queryByCriteria) 645 throws RiceIllegalArgumentException { 646 incomingParamCheck(queryByCriteria, "queryByCriteria"); 647 648 LookupCustomizer.Builder<PermissionBo> lc = LookupCustomizer.Builder.create(); 649 lc.setPredicateTransform(AttributeTransform.getInstance()); 650 651 GenericQueryResults<PermissionBo> results = criteriaLookupService.lookup(PermissionBo.class, queryByCriteria, lc.build()); 652 653 PermissionQueryResults.Builder builder = PermissionQueryResults.Builder.create(); 654 builder.setMoreResultsAvailable(results.isMoreResultsAvailable()); 655 builder.setTotalRowCount(results.getTotalRowCount()); 656 657 final List<Permission.Builder> ims = new ArrayList<Permission.Builder>(); 658 for (PermissionBo bo : results.getResults()) { 659 ims.add(Permission.Builder.create(bo)); 660 } 661 662 builder.setResults(ims); 663 return builder.build(); 664 } 665 666 @Override 667 public TemplateQueryResults findPermissionTemplates(final QueryByCriteria queryByCriteria) 668 throws RiceIllegalArgumentException { 669 incomingParamCheck(queryByCriteria, "queryByCriteria"); 670 671 GenericQueryResults<PermissionTemplateBo> results = criteriaLookupService.lookup(PermissionTemplateBo.class, queryByCriteria); 672 673 TemplateQueryResults.Builder builder = TemplateQueryResults.Builder.create(); 674 builder.setMoreResultsAvailable(results.isMoreResultsAvailable()); 675 builder.setTotalRowCount(results.getTotalRowCount()); 676 677 final List<Template.Builder> ims = new ArrayList<Template.Builder>(); 678 for (PermissionTemplateBo bo : results.getResults()) { 679 ims.add(Template.Builder.create(bo)); 680 } 681 682 builder.setResults(ims); 683 return builder.build(); 684 } 685 686 private List<String> getRoleIdsForPermissions( Collection<Permission> permissions ) { 687 if (CollectionUtils.isEmpty(permissions)) { 688 return Collections.emptyList(); 689 } 690 List<String> ids = new ArrayList<String>(); 691 for (Permission p : permissions) { 692 ids.add(p.getId()); 693 } 694 695 return getRoleIdsForPermissionIds(ids); 696 } 697 698 private List<String> getRoleIdsForPermissionIds(Collection<String> permissionIds) { 699 if (CollectionUtils.isEmpty(permissionIds)) { 700 return Collections.emptyList(); 701 } 702 String cacheKey = new StringBuilder("{getRoleIdsForPermissionIds}") 703 .append("permissionIds=").append(CacheKeyUtils.key(permissionIds)).toString(); 704 Cache.ValueWrapper cachedValue = cacheManager.getCache(Permission.Cache.NAME).get(cacheKey); 705 if (cachedValue != null && cachedValue.get() instanceof List) { 706 return ((List<String>)cachedValue.get()); 707 } 708 QueryByCriteria query = QueryByCriteria.Builder.fromPredicates(equal("active", "true"), in("permissionId", permissionIds.toArray(new String[]{}))); 709 GenericQueryResults<RolePermissionBo> results = criteriaLookupService.lookup(RolePermissionBo.class, query); 710 List<String> roleIds = new ArrayList<String>(); 711 for (RolePermissionBo bo : results.getResults()) { 712 roleIds.add(bo.getRoleId()); 713 } 714 roleIds = Collections.unmodifiableList(roleIds); 715 cacheManager.getCache(Permission.Cache.NAME).put(cacheKey, roleIds); 716 return roleIds; 717 } 718 719 /** 720 * Sets the kimTypeInfoService attribute value. 721 * 722 * @param kimTypeInfoService The kimTypeInfoService to set. 723 */ 724 public void setKimTypeInfoService(KimTypeInfoService kimTypeInfoService) { 725 this.kimTypeInfoService = kimTypeInfoService; 726 } 727 728 /** 729 * Sets the defaultPermissionTypeService attribute value. 730 * 731 * @param defaultPermissionTypeService The defaultPermissionTypeService to set. 732 */ 733 public void setDefaultPermissionTypeService(PermissionTypeService defaultPermissionTypeService) { 734 this.defaultPermissionTypeService = defaultPermissionTypeService; 735 } 736 737 /** 738 * Sets the roleService attribute value. 739 * 740 * @param roleService The roleService to set. 741 */ 742 public void setRoleService(RoleService roleService) { 743 this.roleService = roleService; 744 } 745 746 /** 747 * Sets the businessObjectService attribute value. 748 * 749 * @param businessObjectService The businessObjectService to set. 750 */ 751 public void setBusinessObjectService(final BusinessObjectService businessObjectService) { 752 this.businessObjectService = businessObjectService; 753 } 754 755 /** 756 * Sets the criteriaLookupService attribute value. 757 * 758 * @param criteriaLookupService The criteriaLookupService to set. 759 */ 760 public void setCriteriaLookupService(final CriteriaLookupService criteriaLookupService) { 761 this.criteriaLookupService = criteriaLookupService; 762 } 763 764 /** 765 * Sets the cache manager which this service implementation can for internal caching. 766 * Calling this setter is optional, though the value passed to it must not be null. 767 * 768 * @param cacheManager the cache manager to use for internal caching, must not be null 769 * @throws IllegalArgumentException if a null cache manager is passed 770 */ 771 public void setCacheManager(final CacheManager cacheManager) { 772 if (cacheManager == null) { 773 throw new IllegalArgumentException("cacheManager must not be null"); 774 } 775 this.cacheManager = cacheManager; 776 } 777 778 private List<Permission> toPermissions(Collection<PermissionBo> permissionBos) { 779 if (CollectionUtils.isEmpty(permissionBos)) { 780 return new ArrayList<Permission>(); 781 } 782 List<Permission> permissions = new ArrayList<Permission>(permissionBos.size()); 783 for (PermissionBo permissionBo : permissionBos) { 784 permissions.add(PermissionBo.to(permissionBo)); 785 } 786 return permissions; 787 } 788 789 protected void logAuthorizationCheck(String checkType, String principalId, String namespaceCode, String permissionName, Map<String, String> qualification ) { 790 StringBuilder sb = new StringBuilder(); 791 sb.append( '\n' ); 792 sb.append( "Is AuthZ for " ).append( checkType ).append( ": " ).append( namespaceCode ).append( "/" ).append( permissionName ).append( '\n' ); 793 sb.append( " Principal: " ).append( principalId ); 794 if ( principalId != null ) { 795 Principal principal = KimApiServiceLocator.getIdentityService().getPrincipal(principalId); 796 if ( principal != null ) { 797 sb.append( " (" ).append( principal.getPrincipalName() ).append( ')' ); 798 } 799 } 800 sb.append( '\n' ); 801 sb.append( " Qualifiers:\n" ); 802 if ( qualification != null && !qualification.isEmpty() ) { 803 sb.append( qualification ); 804 } else { 805 sb.append( " [null]\n" ); 806 } 807 if (LOG.isTraceEnabled()) { 808 LOG.trace( sb.append(ExceptionUtils.getStackTrace(new Throwable()))); 809 } else { 810 LOG.debug(sb.toString()); 811 } 812 } 813 814 protected void logAuthorizationCheckByTemplate(String checkType, String principalId, String namespaceCode, String permissionName, 815 Map<String, String> permissionDetails, Map<String, String> qualification ) { 816 StringBuilder sb = new StringBuilder(); 817 sb.append( '\n' ); 818 sb.append( "Is AuthZ for " ).append( checkType ).append( ": " ).append( namespaceCode ).append( "/" ).append( permissionName ).append( '\n' ); 819 sb.append( " Principal: " ).append( principalId ); 820 if ( principalId != null ) { 821 Principal principal = KimApiServiceLocator.getIdentityService().getPrincipal(principalId); 822 if ( principal != null ) { 823 sb.append( " (" ).append( principal.getPrincipalName() ).append( ')' ); 824 } 825 } 826 sb.append( '\n' ); 827 sb.append( " Details:\n" ); 828 if ( permissionDetails != null ) { 829 sb.append( permissionDetails ); 830 } else { 831 sb.append( " [null]\n" ); 832 } 833 sb.append( " Qualifiers:\n" ); 834 if ( qualification != null && !qualification.isEmpty() ) { 835 sb.append( qualification ); 836 } else { 837 sb.append( " [null]\n" ); 838 } 839 if (LOG.isTraceEnabled()) { 840 LOG.trace( sb.append(ExceptionUtils.getStackTrace(new Throwable()))); 841 } else { 842 LOG.debug(sb.toString()); 843 } 844 } 845 846 private void incomingParamCheck(Object object, String name) { 847 if (object == null) { 848 throw new RiceIllegalArgumentException(name + " was null"); 849 } else if (object instanceof String 850 && StringUtils.isBlank((String) object)) { 851 throw new RiceIllegalArgumentException(name + " was blank"); 852 } 853 } 854 855 856}