View Javadoc
1   /*
2    * Copyright 2009 The Kuali Foundation.
3    *
4    * Licensed under the Educational Community License, Version 1.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl1.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.sec.service.impl;
17  
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.Collections;
21  import java.util.HashMap;
22  import java.util.List;
23  import java.util.Map;
24  
25  import org.apache.commons.lang.StringUtils;
26  import org.kuali.ole.integration.cg.ContractsAndGrantsModuleService;
27  import org.kuali.ole.sec.SecConstants;
28  import org.kuali.ole.sec.SecConstants.SecurityTemplateNames;
29  import org.kuali.ole.sec.businessobject.AccessSecurityRestrictionInfo;
30  import org.kuali.ole.sec.datadictionary.AccessSecurityAttributeRestrictionEntry;
31  import org.kuali.ole.sec.identity.SecKimAttributes;
32  import org.kuali.ole.sec.service.AccessPermissionEvaluator;
33  import org.kuali.ole.sec.service.AccessSecurityService;
34  import org.kuali.ole.sys.OLEConstants;
35  import org.kuali.ole.sys.businessobject.AccountingLine;
36  import org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntry;
37  import org.kuali.ole.sys.businessobject.ReportBusinessObject;
38  import org.kuali.ole.sys.businessobject.SourceAccountingLine;
39  import org.kuali.ole.sys.businessobject.TargetAccountingLine;
40  import org.kuali.ole.sys.businessobject.datadictionary.FinancialSystemBusinessObjectEntry;
41  import org.kuali.ole.sys.document.AccountingDocument;
42  import org.kuali.rice.core.api.config.property.ConfigurationService;
43  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
44  import org.kuali.rice.kew.api.WorkflowDocument;
45  import org.kuali.rice.kim.api.KimConstants;
46  import org.kuali.rice.kim.api.common.template.Template;
47  import org.kuali.rice.kim.api.identity.Person;
48  import org.kuali.rice.kim.api.permission.Permission;
49  import org.kuali.rice.kim.api.permission.PermissionService;
50  import org.kuali.rice.kim.api.role.RoleService;
51  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
52  import org.kuali.rice.kns.service.DataDictionaryService;
53  import org.kuali.rice.krad.bo.BusinessObject;
54  import org.kuali.rice.krad.bo.PersistableBusinessObject;
55  import org.kuali.rice.krad.datadictionary.AttributeDefinition;
56  import org.kuali.rice.krad.document.Document;
57  import org.kuali.rice.krad.util.GlobalVariables;
58  import org.kuali.rice.krad.util.ObjectUtils;
59  
60  
61  /**
62   * @see org.kuali.ole.sec.service.AccessSecurityService
63   */
64  public class AccessSecurityServiceImpl implements AccessSecurityService {
65      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AccessSecurityServiceImpl.class);
66  
67      protected DataDictionaryService dataDictionaryService;
68      protected ParameterService parameterService;
69      private PermissionService permissionService;
70      private RoleService roleService;
71      protected ContractsAndGrantsModuleService contractsAndGrantsModuleService;
72      protected ConfigurationService configurationService;
73  
74      /**
75       * @see org.kuali.ole.sec.service.AccessSecurityService#applySecurityRestrictionsForGLInquiry(java.util.List, org.kuali.rice.kim.api.identity.Person)
76       */
77      @Override
78      public void applySecurityRestrictionsForGLInquiry(List<? extends BusinessObject> results, Person person) {
79          applySecurityRestrictions(results, person, getInquiryWithFieldValueTemplate(), Collections.singletonMap(KimConstants.AttributeConstants.NAMESPACE_CODE, OLEConstants.CoreModuleNamespaces.GL));
80      }
81  
82      /**
83       * @see org.kuali.ole.sec.service.AccessSecurityService#applySecurityRestrictionsForLookup(java.util.List, org.kuali.rice.kim.api.identity.Person)
84       */
85      @Override
86      public void applySecurityRestrictionsForLookup(List<? extends BusinessObject> results, Person person) {
87          applySecurityRestrictions(results, person, getLookupWithFieldValueTemplate(), null);
88      }
89  
90      /**
91       * Retrieves any setup security permissions for the given person and evaluates against List of business objects. Any instances
92       * not passing validation are removed from given list.
93       *
94       * @param results List of business object instances with data to check
95       * @param person Person to apply security for
96       * @param templateId KIM template id for permissions to check
97       * @param additionalPermissionDetails Any additional details that should be matched on when retrieving permissions
98       */
99      @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 }