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