001/* 002 * Copyright 2009 The Kuali Foundation. 003 * 004 * Licensed under the Educational Community License, Version 1.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/ecl1.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.ole.sec.service.impl; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.Collections; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024 025import org.apache.commons.lang.StringUtils; 026import org.kuali.ole.integration.cg.ContractsAndGrantsModuleService; 027import org.kuali.ole.sec.SecConstants; 028import org.kuali.ole.sec.SecConstants.SecurityTemplateNames; 029import org.kuali.ole.sec.businessobject.AccessSecurityRestrictionInfo; 030import org.kuali.ole.sec.datadictionary.AccessSecurityAttributeRestrictionEntry; 031import org.kuali.ole.sec.identity.SecKimAttributes; 032import org.kuali.ole.sec.service.AccessPermissionEvaluator; 033import org.kuali.ole.sec.service.AccessSecurityService; 034import org.kuali.ole.sys.OLEConstants; 035import org.kuali.ole.sys.businessobject.AccountingLine; 036import org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntry; 037import org.kuali.ole.sys.businessobject.ReportBusinessObject; 038import org.kuali.ole.sys.businessobject.SourceAccountingLine; 039import org.kuali.ole.sys.businessobject.TargetAccountingLine; 040import org.kuali.ole.sys.businessobject.datadictionary.FinancialSystemBusinessObjectEntry; 041import org.kuali.ole.sys.document.AccountingDocument; 042import org.kuali.rice.core.api.config.property.ConfigurationService; 043import org.kuali.rice.coreservice.framework.parameter.ParameterService; 044import org.kuali.rice.kew.api.WorkflowDocument; 045import org.kuali.rice.kim.api.KimConstants; 046import org.kuali.rice.kim.api.common.template.Template; 047import org.kuali.rice.kim.api.identity.Person; 048import org.kuali.rice.kim.api.permission.Permission; 049import org.kuali.rice.kim.api.permission.PermissionService; 050import org.kuali.rice.kim.api.role.RoleService; 051import org.kuali.rice.kim.api.services.KimApiServiceLocator; 052import org.kuali.rice.kns.service.DataDictionaryService; 053import org.kuali.rice.krad.bo.BusinessObject; 054import org.kuali.rice.krad.bo.PersistableBusinessObject; 055import org.kuali.rice.krad.datadictionary.AttributeDefinition; 056import org.kuali.rice.krad.document.Document; 057import org.kuali.rice.krad.util.GlobalVariables; 058import org.kuali.rice.krad.util.ObjectUtils; 059 060 061/** 062 * @see org.kuali.ole.sec.service.AccessSecurityService 063 */ 064public class AccessSecurityServiceImpl implements AccessSecurityService { 065 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AccessSecurityServiceImpl.class); 066 067 protected DataDictionaryService dataDictionaryService; 068 protected ParameterService parameterService; 069 private PermissionService permissionService; 070 private RoleService roleService; 071 protected ContractsAndGrantsModuleService contractsAndGrantsModuleService; 072 protected ConfigurationService configurationService; 073 074 /** 075 * @see org.kuali.ole.sec.service.AccessSecurityService#applySecurityRestrictionsForGLInquiry(java.util.List, org.kuali.rice.kim.api.identity.Person) 076 */ 077 @Override 078 public void applySecurityRestrictionsForGLInquiry(List<? extends BusinessObject> results, Person person) { 079 applySecurityRestrictions(results, person, getInquiryWithFieldValueTemplate(), Collections.singletonMap(KimConstants.AttributeConstants.NAMESPACE_CODE, OLEConstants.CoreModuleNamespaces.GL)); 080 } 081 082 /** 083 * @see org.kuali.ole.sec.service.AccessSecurityService#applySecurityRestrictionsForLookup(java.util.List, org.kuali.rice.kim.api.identity.Person) 084 */ 085 @Override 086 public void applySecurityRestrictionsForLookup(List<? extends BusinessObject> results, Person person) { 087 applySecurityRestrictions(results, person, getLookupWithFieldValueTemplate(), null); 088 } 089 090 /** 091 * Retrieves any setup security permissions for the given person and evaluates against List of business objects. Any instances 092 * not passing validation are removed from given list. 093 * 094 * @param results List of business object instances with data to check 095 * @param person Person to apply security for 096 * @param templateId KIM template id for permissions to check 097 * @param additionalPermissionDetails Any additional details that should be matched on when retrieving permissions 098 */ 099 @Override 100 public void applySecurityRestrictions(List<? extends BusinessObject> results, Person person, Template permissionTemplate, Map<String,String> additionalPermissionDetails) { 101 if (!isAccessSecurityEnabled()) { 102 return; 103 } 104 105 if (results == null || results.isEmpty()) { 106 return; 107 } 108 109 // evaluate permissions against business object instances 110 List<BusinessObject> restrictedRecords = new ArrayList<BusinessObject>(); 111 for (BusinessObject businessObject : results) { 112 boolean accessAllowed = evaluateSecurityPermissionsByTemplate(businessObject, businessObject.getClass(), person, permissionTemplate, additionalPermissionDetails, null); 113 if (!accessAllowed) { 114 restrictedRecords.add(businessObject); 115 } 116 } 117 118 // remove restricted records from result list 119 for (BusinessObject businessObject : restrictedRecords) { 120 results.remove(businessObject); 121 } 122 } 123 124 /** 125 * @see org.kuali.ole.sec.service.AccessSecurityService#canEditDocumentAccountingLine(org.kuali.ole.sys.document.AccountingDocument, 126 * org.kuali.ole.sys.businessobject.AccountingLine, org.kuali.rice.kim.api.identity.Person, 127 * org.kuali.ole.sec.businessobject.AccessSecurityRestrictionInfo) 128 */ 129 @Override 130 public boolean canEditDocumentAccountingLine(AccountingDocument document, AccountingLine accountingLine, Person person, AccessSecurityRestrictionInfo restrictionInfo) { 131 // check for edit line overrides 132 boolean meetsOverrideCondition = checkForEditLineOverrides(document, accountingLine, person); 133 if (meetsOverrideCondition) { 134 return true; 135 } 136 137 Class<?> entryClass = SourceAccountingLine.class; 138 if (TargetAccountingLine.class.isAssignableFrom(accountingLine.getClass())) { 139 entryClass = TargetAccountingLine.class; 140 } 141 142 if (restrictionInfo != null) { 143 restrictionInfo.setDocumentNumber(document.getDocumentNumber()); 144 } 145 146 return evaluateSecurityPermissionsByTemplate(accountingLine, entryClass, person, getEditAccountingLineWithFieldValueTemplate(), getDocumentTypeDetail(document), restrictionInfo); 147 } 148 149 /** 150 * @see org.kuali.ole.sec.service.AccessSecurityService#canEditDocumentAccountingLine(org.kuali.ole.sys.document.AccountingDocument, 151 * org.kuali.ole.sys.businessobject.AccountingLine, org.kuali.rice.kim.api.identity.Person) 152 */ 153 @Override 154 public boolean canEditDocumentAccountingLine(AccountingDocument document, AccountingLine accountingLine, Person person) { 155 return canEditDocumentAccountingLine(document, accountingLine, person, new AccessSecurityRestrictionInfo()); 156 } 157 158 /** 159 * @see org.kuali.ole.sec.service.AccessSecurityService#canViewDocument(org.kuali.ole.sys.document.AccountingDocument, 160 * org.kuali.rice.kim.api.identity.Person, org.kuali.ole.sec.businessobject.AccessSecurityRestrictionInfo) 161 */ 162 @Override 163 public boolean canViewDocument(AccountingDocument document, Person person, AccessSecurityRestrictionInfo restrictionInfo) { 164 // any workflow requests override view document access permissions 165 boolean hasWorkflowRequests = checkForWorkflowRoutingRequests(document, person); 166 if (hasWorkflowRequests) { 167 return true; 168 } 169 170 // check for parameter overrides 171 boolean meetsOverrideCondition = checkForViewDocumentOverrides(document, person); 172 if (meetsOverrideCondition) { 173 return true; 174 } 175 176 if (restrictionInfo != null) { 177 restrictionInfo.setDocumentNumber(document.getDocumentNumber()); 178 } 179 180 return evaluateSecurityOnAccountingLinesByTemplate(document, person, getViewDocumentWithFieldValueTemplate(), restrictionInfo); 181 } 182 183 /** 184 * @see org.kuali.ole.sec.service.AccessSecurityService#canViewDocumentAccountingLine(org.kuali.ole.sys.document.AccountingDocument, 185 * org.kuali.ole.sys.businessobject.AccountingLine, org.kuali.rice.kim.api.identity.Person) 186 */ 187 @Override 188 public boolean canViewDocumentAccountingLine(AccountingDocument document, AccountingLine accountingLine, Person person) { 189 // check for view line overrides 190 boolean meetsOverrideCondition = checkForViewLineOverrides(document, accountingLine, person); 191 if (meetsOverrideCondition) { 192 return true; 193 } 194 195 Class entryClass = SourceAccountingLine.class; 196 if (TargetAccountingLine.class.isAssignableFrom(accountingLine.getClass())) { 197 entryClass = TargetAccountingLine.class; 198 } 199 200 return evaluateSecurityPermissionsByTemplate(accountingLine, entryClass, person, getViewAccountingLineWithFieldValueTemplate(), getDocumentTypeDetail(document), null); 201 } 202 203 /** 204 * @see org.kuali.ole.sec.service.AccessSecurityService#canViewDocumentNotesAttachments(org.kuali.ole.sys.document.AccountingDocument, 205 * org.kuali.rice.kim.api.identity.Person) 206 */ 207 @Override 208 public boolean canViewDocumentNotesAttachments(AccountingDocument document, Person person) { 209 // check for parameter overrides 210 boolean meetsOverrideCondition = checkForViewDocumentOverrides(document, person); 211 if (meetsOverrideCondition) { 212 return true; 213 } 214 215 return evaluateSecurityOnAccountingLinesByTemplate(document, person, getViewNotesAttachmentsWithFieldValueTemplate(), null); 216 } 217 218 /** 219 * Iterates through source and target accounting lines for the given document and evaluates any permissions with the given 220 * template id against the accounting line values 221 * 222 * @param document AccountingDocument instance with accounting lines to check, doc type of instance is used for retrieving 223 * permissions 224 * @param person the user who we are checking access for 225 * @param templateId KIM template id for the permissions to check 226 * @param restrictionInfo Object providing information on a restriction if one is found 227 * @return boolean true if all accounting lines pass permissions, false if at least one accounting line does not pass 228 */ 229 protected boolean evaluateSecurityOnAccountingLinesByTemplate(AccountingDocument document, Person person, Template permissionTemplate, AccessSecurityRestrictionInfo restrictionInfo) { 230 boolean success = true; 231 232 if (!isAccessSecurityEnabled()) { 233 return success; 234 } 235 236 Map<String,String> permissionDetails = getDocumentTypeDetail(document); 237 238 // check source lines 239 for ( AccountingLine accountingLine : (List<AccountingLine>)document.getSourceAccountingLines() ) { 240 241 // check for overrides 242 boolean meetsOverrideCondition = false; 243 if (permissionTemplate.getId().equals(getViewDocumentWithFieldValueTemplate().getId())) { 244 meetsOverrideCondition = checkForViewLineOverrides(document, accountingLine, person); 245 } 246 else { 247 meetsOverrideCondition = checkForEditLineOverrides(document, accountingLine, person); 248 } 249 250 if (meetsOverrideCondition) { 251 continue; 252 } 253 254 success = evaluateSecurityPermissionsByTemplate(accountingLine, SourceAccountingLine.class, person, permissionTemplate, permissionDetails, restrictionInfo); 255 if (!success) { 256 break; 257 } 258 } 259 260 // if source lines are ok, check target lines 261 if (success) { 262 for ( AccountingLine accountingLine : (List<AccountingLine>)document.getTargetAccountingLines() ) { 263 // check for overrides 264 boolean meetsOverrideCondition = false; 265 if (permissionTemplate.equals(getViewDocumentWithFieldValueTemplate())) { 266 meetsOverrideCondition = checkForViewLineOverrides(document, accountingLine, person); 267 } 268 else { 269 meetsOverrideCondition = checkForEditLineOverrides(document, accountingLine, person); 270 } 271 272 if (meetsOverrideCondition) { 273 continue; 274 } 275 276 success = evaluateSecurityPermissionsByTemplate(accountingLine, TargetAccountingLine.class, person, permissionTemplate, permissionDetails, restrictionInfo); 277 if (!success) { 278 break; 279 } 280 } 281 } 282 283 return success; 284 } 285 286 /** 287 * Checks for any workflow requests (approve, acknowledge, fyi) for the document to the given person 288 * 289 * @param document Document to check for routing requests 290 * @param person Person to check for routing requests 291 * @return boolean true if there are workflow requests, false if not 292 */ 293 protected boolean checkForWorkflowRoutingRequests(AccountingDocument document, Person person) { 294 WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument(); 295 296 return workflowDocument.isApprovalRequested() || workflowDocument.isAcknowledgeRequested() || workflowDocument.isFYIRequested(); 297 } 298 299 /** 300 * Checks parameter overrides for view document permission. Currently only have initiator override parameter 301 * 302 * @param document Document that we are checking permissions for 303 * @param person Person we are checking permissions for 304 * @return boolean true if overrides are turned on and the person meets the override conditions, false if overrides are not 305 * turned on or the person does not meet condition 306 */ 307 protected boolean checkForViewDocumentOverrides(AccountingDocument document, Person person) { 308 boolean alwaysAllowInitiatorAccess = parameterService.getParameterValueAsBoolean(SecConstants.ACCESS_SECURITY_NAMESPACE_CODE, SecConstants.ALL_PARAMETER_DETAIL_COMPONENT, SecConstants.SecurityParameterNames.ALWAYS_ALLOW_INITIATOR_DOCUMENT_ACCESS_IND); 309 if (alwaysAllowInitiatorAccess) { 310 WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument(); 311 if (StringUtils.equals(workflowDocument.getInitiatorPrincipalId(), person.getPrincipalId())) { 312 return true; 313 } 314 } 315 316 return false; 317 } 318 319 /** 320 * Checks parameter overrides for view line permission. Currently only have initiator, fiscal officer, and principal 321 * investigator overrides 322 * 323 * @param document Document that we are checking permissions for 324 * @param person Person we are checking permissions for 325 * @param line AccountingLine we are checking permissions for 326 * @return boolean true if any override is turned on and the person meets the override conditions, false otherwise 327 */ 328 protected boolean checkForViewLineOverrides(AccountingDocument document, AccountingLine line, Person person) { 329 // initiator override 330 boolean alwaysAllowInitiatorAccess = parameterService.getParameterValueAsBoolean(SecConstants.ACCESS_SECURITY_NAMESPACE_CODE, SecConstants.ALL_PARAMETER_DETAIL_COMPONENT, SecConstants.SecurityParameterNames.ALWAYS_ALLOW_INITIATOR_LINE_ACCESS_IND); 331 if (alwaysAllowInitiatorAccess) { 332 WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument(); 333 if (StringUtils.equals(workflowDocument.getInitiatorPrincipalId(), person.getPrincipalId())) { 334 return true; 335 } 336 } 337 338 // account must be not be empty for further override checks 339 if (line.getAccount() == null) { 340 return false; 341 } 342 343 // fiscal officer override 344 boolean alwaysAllowFOAccess = parameterService.getParameterValueAsBoolean(SecConstants.ACCESS_SECURITY_NAMESPACE_CODE, SecConstants.ALL_PARAMETER_DETAIL_COMPONENT, SecConstants.SecurityParameterNames.ALWAYS_ALLOW_FISCAL_OFFICER_LINE_ACCESS_IND); 345 if (alwaysAllowFOAccess) { 346 if (StringUtils.equals(line.getAccount().getAccountFiscalOfficerSystemIdentifier(), person.getPrincipalId())) { 347 return true; 348 } 349 } 350 351 // pi override 352 boolean alwaysAllowPIAccess = parameterService.getParameterValueAsBoolean(SecConstants.ACCESS_SECURITY_NAMESPACE_CODE, SecConstants.ALL_PARAMETER_DETAIL_COMPONENT, SecConstants.SecurityParameterNames.ALWAYS_ALLOW_PRINCIPAL_INVESTIGATOR_LINE_ACCESS_IND); 353 if (alwaysAllowPIAccess) { 354 Person principalInvestigator = contractsAndGrantsModuleService.getProjectDirectorForAccount(line.getAccount()); 355 if (principalInvestigator != null && StringUtils.equals(principalInvestigator.getPrincipalId(), person.getPrincipalId())) { 356 return true; 357 } 358 } 359 360 return false; 361 } 362 363 /** 364 * Checks parameter overrides for edit line permission. Currently only have fiscal officer and principal investigator overrides 365 * 366 * @param document Document that we are checking permissions for 367 * @param person Person we are checking permissions for 368 * @param line AccountingLine we are checking permissions for 369 * @return boolean true if any override is turned on and the person meets the override conditions, false otherwise 370 */ 371 protected boolean checkForEditLineOverrides(AccountingDocument document, AccountingLine line, Person person) { 372 // account must not be empty for override checks 373 if (ObjectUtils.isNull(line.getAccount()) || line.getAccountNumber() == null) { 374 return false; 375 } 376 377 // fiscal officer override 378 boolean alwaysAllowFOAccess = parameterService.getParameterValueAsBoolean(SecConstants.ACCESS_SECURITY_NAMESPACE_CODE, SecConstants.ALL_PARAMETER_DETAIL_COMPONENT, SecConstants.SecurityParameterNames.ALWAYS_ALLOW_FISCAL_OFFICER_LINE_ACCESS_IND); 379 if (alwaysAllowFOAccess) { 380 if (StringUtils.equals(line.getAccount().getAccountFiscalOfficerSystemIdentifier(), person.getPrincipalId())) { 381 return true; 382 } 383 } 384 385 // pi override 386 boolean alwaysAllowPIAccess = parameterService.getParameterValueAsBoolean(SecConstants.ACCESS_SECURITY_NAMESPACE_CODE, SecConstants.ALL_PARAMETER_DETAIL_COMPONENT, SecConstants.SecurityParameterNames.ALWAYS_ALLOW_PRINCIPAL_INVESTIGATOR_LINE_ACCESS_IND); 387 if (alwaysAllowPIAccess) { 388 Person principalInvestigator = contractsAndGrantsModuleService.getProjectDirectorForAccount(line.getAccount()); 389 if (principalInvestigator != null && StringUtils.equals(principalInvestigator.getPrincipalId(), person.getPrincipalId())) { 390 return true; 391 } 392 } 393 394 return false; 395 } 396 397 /** 398 * Validates any security permissions setup for the user and attributes of the class against the business object values 399 * 400 * @param businessObject instance with attribute values to validate 401 * @param entryClass Class of business object to pull attribute restrictions for 402 * @param person the user who we are checking access for 403 * @param templateId type of security permissions to check 404 * @param additionalPermissionDetails any additional details that should be used for retrieving permissions 405 * @param restrictionInfo Object providing information on a restriction if one is found 406 * @return boolean true if user has access given by template to the business object, false otherwise 407 */ 408 protected boolean evaluateSecurityPermissionsByTemplate(BusinessObject businessObject, Class entryClass, Person person, Template permissionTemplate, Map<String,String> additionalPermissionDetails, AccessSecurityRestrictionInfo restrictionInfo) { 409 boolean success = true; 410 411 if (!isAccessSecurityEnabled()) { 412 return success; 413 } 414 415 // get all configured restricted attributes for this business object through it data dictionary entry 416 FinancialSystemBusinessObjectEntry businessObjectEntry = (FinancialSystemBusinessObjectEntry) dataDictionaryService.getDataDictionary().getBusinessObjectEntryForConcreteClass(entryClass.getName()); 417 418 //if the business object is of class ReportBusinessObject interface, use refreshNonUpdateableForReport(); 419 if (ReportBusinessObject.class.isAssignableFrom(businessObject.getClass())) { 420 ((ReportBusinessObject) businessObject).refreshNonUpdateableForReport(); 421 } 422 else if (PersistableBusinessObject.class.isAssignableFrom(businessObject.getClass())) { 423 ((PersistableBusinessObject) businessObject).refreshNonUpdateableReferences(); 424 } else { 425 businessObject.refresh(); 426 } 427 428 for (AccessSecurityAttributeRestrictionEntry accessRestrictedAttribute : businessObjectEntry.getAccessRestrictedAttributes()) { 429 Map<String,String> permissionDetails = new HashMap<String,String>(); 430 permissionDetails.put(KimConstants.AttributeConstants.PROPERTY_NAME, accessRestrictedAttribute.getSecurityAttributeName()); 431 432 if (additionalPermissionDetails != null) { 433 permissionDetails.putAll(additionalPermissionDetails); 434 } 435 436 List<Permission> permissions = getPermissionService().getAuthorizedPermissionsByTemplate(person.getPrincipalId(), permissionTemplate.getNamespaceCode(), permissionTemplate.getName(), permissionDetails, new HashMap<String, String>(0)); 437 if (permissions == null || permissions.isEmpty()) { 438 continue; 439 } 440 441 // retrieve field value to check 442 Object propertyValue = ObjectUtils.getPropertyValue(businessObject, accessRestrictedAttribute.getAttribute().getName()); 443 if (propertyValue != null && StringUtils.isNotEmpty(propertyValue.toString())) { 444 // retrieve other field values that might be necessary to validate main field 445 Map<String, Object> otherKeyValues = new HashMap<String, Object>(); 446 for (String keyFieldName : accessRestrictedAttribute.getOtherKeyFields().keySet()) { 447 AttributeDefinition fieldDefinition = accessRestrictedAttribute.getOtherKeyFields().get(keyFieldName); 448 449 Object keyFieldValue = ObjectUtils.getPropertyValue(businessObject, fieldDefinition.getName()); 450 otherKeyValues.put(keyFieldName, keyFieldValue); 451 } 452 453 success = evaluateSecurityPermissions(accessRestrictedAttribute.getAccessPermissionEvaluatorClass(), permissions, propertyValue.toString(), person, otherKeyValues); 454 if (!success) { 455 if (restrictionInfo != null) { 456 restrictionInfo.setSecurityAttributeName(accessRestrictedAttribute.getSecurityAttributeName()); 457 restrictionInfo.setPropertyName(accessRestrictedAttribute.getAttribute().getName()); 458 restrictionInfo.setPropertyLabel(accessRestrictedAttribute.getAttribute().getLabel()); 459 restrictionInfo.setRetrictedValue((String) propertyValue); 460 } 461 462 break; 463 } 464 } 465 } 466 467 return success; 468 } 469 470 /** 471 * Constructs a new Map<String,String> and adds document type name detail with value from document instance 472 * 473 * @param document AccountingDocument instance which document type will be set from 474 * @return Map<String,String> containing document type name detail 475 */ 476 protected Map<String,String> getDocumentTypeDetail(AccountingDocument document) { 477 Map<String,String> details = new HashMap<String,String>(); 478 details.put(KimConstants.AttributeConstants.DOCUMENT_TYPE_NAME, document.getFinancialDocumentTypeCode()); 479 480 return details; 481 } 482 483 /** 484 * Checks whether the given value is allowed based on the given permissions and user 485 * 486 * @param accessPermissionEvaluatorClass Class of type AccessPermissionEvaluator that will be used to evaluate the security 487 * restriction 488 * @param permissions List of permissions to evaluate 489 * @param value the value that will be checked 490 * @param person the user who we are checking access for 491 * @param otherKeyValues Map for other key field name/value pairs 492 * @return boolean true if access is allowed false if not 493 */ 494 protected boolean evaluateSecurityPermissions(Class<? extends AccessPermissionEvaluator> accessPermissionEvaluatorClass, List<Permission> permissions, String value, Person person, Map<String, Object> otherKeyValues) { 495 boolean success = true; 496 497 List<Map<String,String>> qualficationsToEvaluate = new ArrayList<Map<String,String>>(); 498 for (Permission permission : permissions) { 499 // find all roles that have been granted this permission 500 List<String> roleIds = getPermissionService().getRoleIdsForPermission(permission.getNamespaceCode(), permission.getName() ); 501 502 // for all the roles that have this permission, find the users qualification in those roles (if any) 503 List<Map<String,String>> qualfications = getRoleService().getNestedRoleQualifiersForPrincipalByRoleIds(person.getPrincipalId(), roleIds, null); 504 505 if (qualfications != null) { 506 qualficationsToEvaluate.addAll(qualfications); 507 } 508 } 509 510 // cycle through the users qualifications and evaluate against the given value 511 boolean hasAllowQualification = false; 512 boolean allowQualificationSuccess = false; 513 boolean hasDenyFailure = false; 514 boolean hasAllowOverride = false; 515 for (Map<String,String> attributeSet : qualficationsToEvaluate) { 516 AccessPermissionEvaluator accessPermissionEvaluator = constructAccessPermissionEvaluator(accessPermissionEvaluatorClass, attributeSet, otherKeyValues, person); 517 boolean allowed = accessPermissionEvaluator.valueIsAllowed(value); 518 519 // all qualifications with constraint 'D' (deny) must pass 520 String constraintCode = attributeSet.get(SecKimAttributes.CONSTRAINT_CODE); 521 if (!allowed && StringUtils.contains(constraintCode, SecConstants.SecurityConstraintCodes.DENIED)) { 522 hasDenyFailure = true; 523 } 524 525 // if there are any 'A' (allow) qualifications, at least one must succeed 526 if (StringUtils.contains(constraintCode, SecConstants.SecurityConstraintCodes.ALLOWED)) { 527 hasAllowQualification = true; 528 if (allowed) { 529 allowQualificationSuccess = true; 530 531 // check for override of deny 532 String overrideDeny = attributeSet.get(SecKimAttributes.OVERRIDE_DENY); 533 if (Boolean.parseBoolean(overrideDeny)) { 534 hasAllowOverride = true; 535 } 536 } 537 } 538 } 539 540 if ((hasDenyFailure && !hasAllowOverride) || (hasAllowQualification && !allowQualificationSuccess)) { 541 success = false; 542 } 543 544 return success; 545 } 546 547 /** 548 * Constructs a new instance of the AccessPermissionEvaluator class and sets the constraint, operator, and value based on the 549 * given qualification 550 * 551 * @param accessPermissionEvaluatorClass Class to create instance of (must implement AccessPermissionEvaluator interface) 552 * @param attributeSet Map<String,String> containing the qualifier values 553 * @param otherKeyValues Map for other key field name/value pairs 554 * @param person Person who permission should be evaluated for 555 * @return new instance of type AccessPermissionEvaluator 556 * @see org.kuali.ole.sec.service.AccessPermissionEvaluator 557 */ 558 protected AccessPermissionEvaluator constructAccessPermissionEvaluator(Class<? extends AccessPermissionEvaluator> accessPermissionEvaluatorClass, Map<String,String> attributeSet, Map<String, Object> otherKeyValues, Person person) { 559 AccessPermissionEvaluator accessPermissionEvaluator = null; 560 try { 561 accessPermissionEvaluator = accessPermissionEvaluatorClass.newInstance(); 562 } 563 catch (Exception e) { 564 String msg = "Unable to create new instance of AccessPermissionEvaluator class: " + accessPermissionEvaluatorClass.getName(); 565 LOG.error(msg, e); 566 throw new RuntimeException(msg, e); 567 } 568 569 accessPermissionEvaluator.setConstraintCode(attributeSet.get(SecKimAttributes.CONSTRAINT_CODE)); 570 accessPermissionEvaluator.setOperatorCode(attributeSet.get(SecKimAttributes.OPERATOR)); 571 accessPermissionEvaluator.setPropertyValue(attributeSet.get(SecKimAttributes.PROPERTY_VALUE)); 572 accessPermissionEvaluator.setOtherKeyFieldValueMap(otherKeyValues); 573 accessPermissionEvaluator.setPerson(person); 574 575 return accessPermissionEvaluator; 576 } 577 578 /** 579 * Helper method to check system parameter that turns access security on/off 580 * 581 * @return boolean indicating whether access security is turned on (true) or off (false) 582 */ 583 protected boolean isAccessSecurityEnabled() { 584 return parameterService.getParameterValueAsBoolean(SecConstants.ACCESS_SECURITY_NAMESPACE_CODE, SecConstants.ALL_PARAMETER_DETAIL_COMPONENT, SecConstants.SecurityParameterNames.ENABLE_ACCESS_SECURITY); 585 } 586 587 /** 588 * Sets the dataDictionaryService attribute value. 589 * 590 * @param dataDictionaryService The dataDictionaryService to set. 591 */ 592 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) { 593 this.dataDictionaryService = dataDictionaryService; 594 } 595 596 /** 597 * Sets the parameterService attribute value. 598 * 599 * @param parameterService The parameterService to set. 600 */ 601 public void setParameterService(ParameterService parameterService) { 602 this.parameterService = parameterService; 603 } 604 605 public void setConfigurationService(ConfigurationService configurationService) { 606 this.configurationService = configurationService; 607 } 608 609 public PermissionService getPermissionService() { 610 if ( permissionService == null ) { 611 permissionService = KimApiServiceLocator.getPermissionService(); 612 } 613 return permissionService; 614 } 615 616 public RoleService getRoleService() { 617 if ( roleService == null ) { 618 roleService = KimApiServiceLocator.getRoleService(); 619 } 620 return roleService; 621 } 622 623 /** 624 * Sets the contractsAndGrantsModuleService attribute value. 625 * 626 * @param contractsAndGrantsModuleService The contractsAndGrantsModuleService to set. 627 */ 628 public void setContractsAndGrantsModuleService(ContractsAndGrantsModuleService contractsAndGrantsModuleService) { 629 this.contractsAndGrantsModuleService = contractsAndGrantsModuleService; 630 } 631 632 /** 633 * @see org.kuali.ole.sec.service.AccessSecurityService#getEditAccountingLineWithFieldValueTemplateId() 634 */ 635 @Override 636 public Template getEditAccountingLineWithFieldValueTemplate() { 637 Template templateInfo = getPermissionService().findPermTemplateByNamespaceCodeAndName(OLEConstants.CoreModuleNamespaces.ACCESS_SECURITY, SecurityTemplateNames.EDIT_ACCOUNTING_LINE_FIELD_VALUE); 638 if ( templateInfo != null ) { 639 return templateInfo; 640 } else { 641 throw new RuntimeException(SecurityTemplateNames.EDIT_ACCOUNTING_LINE_FIELD_VALUE + " parameter does not exist"); 642 } 643 } 644 645 646 /** 647 * @see org.kuali.ole.sec.service.AccessSecurityService#getEditDocumentWithFieldValueTemplateId() 648 */ 649 @Override 650 public Template getEditDocumentWithFieldValueTemplate() { 651 Template templateInfo = getPermissionService().findPermTemplateByNamespaceCodeAndName(OLEConstants.CoreModuleNamespaces.ACCESS_SECURITY, SecurityTemplateNames.EDIT_DOCUMENT_FIELD_VALUE); 652 if ( templateInfo != null ) { 653 return templateInfo; 654 } else { 655 throw new RuntimeException(SecurityTemplateNames.EDIT_DOCUMENT_FIELD_VALUE + " parameter does not exist"); 656 } 657 } 658 659 660 /** 661 * @see org.kuali.ole.sec.service.AccessSecurityService#getInquiryWithFieldValueTemplateId() 662 */ 663 @Override 664 public Template getInquiryWithFieldValueTemplate() { 665 Template templateInfo = getPermissionService().findPermTemplateByNamespaceCodeAndName(OLEConstants.CoreModuleNamespaces.ACCESS_SECURITY, SecurityTemplateNames.INQUIRY_FIELD_VALUE); 666 if ( templateInfo != null ) { 667 return templateInfo; 668 } else { 669 throw new RuntimeException(SecurityTemplateNames.INQUIRY_FIELD_VALUE + " parameter does not exist"); 670 } 671 } 672 673 674 /** 675 * @see org.kuali.ole.sec.service.AccessSecurityService#getLookupWithFieldValueTemplateId() 676 */ 677 @Override 678 public Template getLookupWithFieldValueTemplate() { 679 Template templateInfo = getPermissionService().findPermTemplateByNamespaceCodeAndName(OLEConstants.CoreModuleNamespaces.ACCESS_SECURITY, SecurityTemplateNames.LOOKUP_FIELD_VALUE); 680 if ( templateInfo != null ) { 681 return templateInfo; 682 } else { 683 throw new RuntimeException(SecurityTemplateNames.LOOKUP_FIELD_VALUE + " parameter does not exist"); 684 } 685 } 686 687 688 /** 689 * @see org.kuali.ole.sec.service.AccessSecurityService#getViewAccountingLineWithFieldValueTemplateId() 690 */ 691 @Override 692 public Template getViewAccountingLineWithFieldValueTemplate() { 693 Template templateInfo = getPermissionService().findPermTemplateByNamespaceCodeAndName(OLEConstants.CoreModuleNamespaces.ACCESS_SECURITY, SecurityTemplateNames.VIEW_ACCOUNTING_LINE_FIELD_VALUE); 694 if ( templateInfo != null ) { 695 return templateInfo; 696 } else { 697 throw new RuntimeException(SecurityTemplateNames.VIEW_ACCOUNTING_LINE_FIELD_VALUE + " parameter does not exist"); 698 } 699 } 700 701 702 /** 703 * @see org.kuali.ole.sec.service.AccessSecurityService#getViewDocumentWithFieldValueTemplateId() 704 */ 705 @Override 706 public Template getViewDocumentWithFieldValueTemplate() { 707 Template templateInfo = getPermissionService().findPermTemplateByNamespaceCodeAndName(OLEConstants.CoreModuleNamespaces.ACCESS_SECURITY, SecurityTemplateNames.VIEW_DOCUMENT_FIELD_VALUE); 708 if ( templateInfo != null ) { 709 return templateInfo; 710 } else { 711 throw new RuntimeException(SecurityTemplateNames.VIEW_DOCUMENT_FIELD_VALUE + " parameter does not exist"); 712 } 713 } 714 715 716 /** 717 * @see org.kuali.ole.sec.service.AccessSecurityService#getViewNotesAttachmentsWithFieldValueTemplateId() 718 */ 719 @Override 720 public Template getViewNotesAttachmentsWithFieldValueTemplate() { 721 Template templateInfo = getPermissionService().findPermTemplateByNamespaceCodeAndName(OLEConstants.CoreModuleNamespaces.ACCESS_SECURITY, SecurityTemplateNames.VIEW_NOTES_ATTACHMENTS_FIELD_VALUE); 722 if ( templateInfo != null ) { 723 return templateInfo; 724 } else { 725 throw new RuntimeException(SecurityTemplateNames.VIEW_NOTES_ATTACHMENTS_FIELD_VALUE + " parameter does not exist"); 726 } 727 } 728 729 /** 730 * Calls access security service to check view access on given GLPE for current user. Access to view the GLPE on the document should be related to the view permissions for an 731 * accounting line with the same account attributes. Called from generalLedgerPendingEntries.tag 732 * 733 * @param pendingEntry GeneralLedgerPendingEntry to check access for 734 * @return boolean true if given user has view permission, false otherwise 735 */ 736 @Override 737 public boolean canViewGLPE(Document document, GeneralLedgerPendingEntry pendingEntry, Person person) { 738 boolean canView = true; 739 740 // If the module has not been loaded, then just skip any further checks as the services will not be defined 741 if ( configurationService.getPropertyValueAsBoolean(SecConstants.ACCESS_SECURITY_MODULE_ENABLED_PROPERTY_NAME) ) { 742 if (document instanceof AccountingDocument) { 743 AccountingLine line = new SourceAccountingLine(); 744 745 line.setPostingYear(pendingEntry.getUniversityFiscalYear()); 746 line.setChartOfAccountsCode(pendingEntry.getChartOfAccountsCode()); 747 line.setAccountNumber(pendingEntry.getAccountNumber()); 748 line.setSubAccountNumber(pendingEntry.getSubAccountNumber()); 749 line.setFinancialObjectCode(pendingEntry.getFinancialObjectCode()); 750 line.setFinancialSubObjectCode(pendingEntry.getFinancialSubObjectCode()); 751 line.setProjectCode(pendingEntry.getProjectCode()); 752 753 line.refreshNonUpdateableReferences(); 754 755 canView = canViewDocumentAccountingLine((AccountingDocument) document, line, GlobalVariables.getUserSession().getPerson()); 756 } 757 } 758 759 return canView; 760 } 761 762 /** 763 * Compares the size of the given list against the given previous size and if different adds an info message 764 * 765 * @param previousListSize int giving previous size of list to compare to 766 * @param results List to get size for and compare 767 * @param messageKey String key of message that should be added 768 */ 769 @Override 770 public void compareListSizeAndAddMessageIfChanged(int previousListSize, List<?> results, String messageKey) { 771 int currentListSize = results.size(); 772 773 if (previousListSize != currentListSize) { 774 GlobalVariables.getMessageMap().putInfo(OLEConstants.GLOBAL_MESSAGES, messageKey, Integer.toString(previousListSize - currentListSize)); 775 } 776 } 777 778 @Override 779 public Collection<String> getAccessSecurityControlledDocumentTypeNames() { 780 return parameterService.getParameterValuesAsString(SecConstants.ACCESS_SECURITY_NAMESPACE_CODE, SecConstants.ALL_PARAMETER_DETAIL_COMPONENT, SecConstants.SecurityParameterNames.ACCESS_SECURITY_DOCUMENT_TYPES); 781 } 782 783 @Override 784 public boolean isAccessSecurityControlledDocumentType(String documentTypeName) { 785 return getAccessSecurityControlledDocumentTypeNames().contains(documentTypeName); 786 } 787}