View Javadoc
1   /**
2    * Copyright 2005-2015 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.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/ecl2.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.rice.kns.service.impl;
17  
18  import java.util.Collection;
19  import java.util.Collections;
20  import java.util.HashMap;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.Map;
24  
25  import org.apache.commons.beanutils.PropertyUtils;
26  import org.apache.commons.collections.CollectionUtils;
27  import org.apache.commons.lang.StringUtils;
28  import org.kuali.rice.core.api.CoreApiServiceLocator;
29  import org.kuali.rice.core.api.config.property.ConfigurationService;
30  import org.kuali.rice.kim.api.KimConstants;
31  import org.kuali.rice.kim.api.identity.Person;
32  import org.kuali.rice.kim.api.permission.PermissionService;
33  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
34  import org.kuali.rice.kns.authorization.BusinessObjectAuthorizer;
35  import org.kuali.rice.kns.bo.authorization.InquiryOrMaintenanceDocumentAuthorizer;
36  import org.kuali.rice.kns.bo.authorization.InquiryOrMaintenanceDocumentPresentationController;
37  import org.kuali.rice.kns.datadictionary.BusinessObjectEntry;
38  import org.kuali.rice.kns.datadictionary.FieldDefinition;
39  import org.kuali.rice.kns.datadictionary.InquiryCollectionDefinition;
40  import org.kuali.rice.kns.datadictionary.InquirySectionDefinition;
41  import org.kuali.rice.kns.datadictionary.MaintainableCollectionDefinition;
42  import org.kuali.rice.kns.datadictionary.MaintainableItemDefinition;
43  import org.kuali.rice.kns.datadictionary.MaintainableSectionDefinition;
44  import org.kuali.rice.kns.datadictionary.MaintenanceDocumentEntry;
45  import org.kuali.rice.kns.document.MaintenanceDocument;
46  import org.kuali.rice.kns.document.authorization.BusinessObjectRestrictions;
47  import org.kuali.rice.kns.document.authorization.BusinessObjectRestrictionsBase;
48  import org.kuali.rice.kns.document.authorization.InquiryOrMaintenanceDocumentRestrictions;
49  import org.kuali.rice.kns.document.authorization.InquiryOrMaintenanceDocumentRestrictionsBase;
50  import org.kuali.rice.kns.document.authorization.MaintenanceDocumentAuthorizer;
51  import org.kuali.rice.kns.document.authorization.MaintenanceDocumentPresentationController;
52  import org.kuali.rice.kns.document.authorization.MaintenanceDocumentRestrictions;
53  import org.kuali.rice.kns.document.authorization.MaintenanceDocumentRestrictionsBase;
54  import org.kuali.rice.kns.inquiry.InquiryAuthorizer;
55  import org.kuali.rice.kns.inquiry.InquiryPresentationController;
56  import org.kuali.rice.kns.inquiry.InquiryRestrictions;
57  import org.kuali.rice.kns.service.BusinessObjectAuthorizationService;
58  import org.kuali.rice.kns.service.BusinessObjectDictionaryService;
59  import org.kuali.rice.kns.service.DocumentHelperService;
60  import org.kuali.rice.kns.service.KNSServiceLocator;
61  import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService;
62  import org.kuali.rice.krad.bo.BusinessObject;
63  import org.kuali.rice.krad.datadictionary.AttributeDefinition;
64  import org.kuali.rice.krad.datadictionary.DataObjectEntry;
65  import org.kuali.rice.krad.document.Document;
66  import org.kuali.rice.krad.service.DataDictionaryService;
67  import org.kuali.rice.krad.service.impl.DataObjectAuthorizationServiceImpl;
68  import org.kuali.rice.krad.util.KRADConstants;
69  import org.kuali.rice.krad.util.KRADUtils;
70  import org.kuali.rice.krad.util.LegacyDataFramework;
71  import org.kuali.rice.krad.util.ObjectUtils;
72  
73  /**
74   * @deprecated Use {@link DataObjectAuthorizationServiceImpl}.
75   */
76  @Deprecated
77  @LegacyDataFramework
78  public class BusinessObjectAuthorizationServiceImpl extends DataObjectAuthorizationServiceImpl implements BusinessObjectAuthorizationService {
79  	private DataDictionaryService dataDictionaryService;
80  	private PermissionService permissionService;
81  	private BusinessObjectDictionaryService businessObjectDictionaryService;
82  	private DocumentHelperService documentHelperService;
83  	private MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
84  	private ConfigurationService kualiConfigurationService;
85  
86  	@Override
87      public BusinessObjectRestrictions getLookupResultRestrictions(
88  			Object dataObject, Person user) {
89  		BusinessObjectRestrictions businessObjectRestrictions = new BusinessObjectRestrictionsBase();
90  		considerBusinessObjectFieldUnmaskAuthorization(dataObject, user,
91  				businessObjectRestrictions, "", null);
92  		return businessObjectRestrictions;
93  	}
94  
95  	@Override
96      public InquiryRestrictions getInquiryRestrictions(
97  			BusinessObject businessObject, Person user) {
98  		InquiryRestrictions inquiryRestrictions = new InquiryOrMaintenanceDocumentRestrictionsBase();
99  		BusinessObjectEntry businessObjectEntry = (BusinessObjectEntry) getDataDictionaryService()
100 				.getDataDictionary().getBusinessObjectEntry(
101 						businessObject.getClass().getName());
102 		InquiryPresentationController inquiryPresentationController = getBusinessObjectDictionaryService()
103 				.getInquiryPresentationController(businessObject.getClass());
104 		InquiryAuthorizer inquiryAuthorizer = getBusinessObjectDictionaryService()
105 				.getInquiryAuthorizer(businessObject.getClass());
106 		considerBusinessObjectFieldUnmaskAuthorization(businessObject, user,
107 				inquiryRestrictions, "", null);
108 		considerBusinessObjectFieldViewAuthorization(businessObjectEntry,
109 				businessObject, null, user, inquiryAuthorizer, inquiryRestrictions,
110 				"");
111 		considerInquiryOrMaintenanceDocumentPresentationController(
112 				inquiryPresentationController, businessObject,
113 				inquiryRestrictions);
114 		considerInquiryOrMaintenanceDocumentAuthorizer(inquiryAuthorizer,
115 				businessObject, user, inquiryRestrictions);
116 		for (InquirySectionDefinition inquirySectionDefinition : businessObjectEntry.getInquiryDefinition().getInquirySections()) {
117 			if (inquirySectionDefinition.getInquiryCollections() != null) {
118 				addInquirableItemRestrictions(inquirySectionDefinition.getInquiryCollections().values(), inquiryAuthorizer,
119 						inquiryRestrictions, businessObject, businessObject, "", user);
120 			}
121 			// Collections may also be stored in the inquiry fields, so we need to parse through that
122 			List<FieldDefinition> inquiryFields = inquirySectionDefinition.getInquiryFields();
123 			if (inquiryFields != null) {
124 				for (FieldDefinition fieldDefinition : inquiryFields) {
125 					addInquirableItemRestrictions(inquiryFields, inquiryAuthorizer,
126 							inquiryRestrictions, businessObject, businessObject, "", user);
127 				}
128 			}
129 		}
130 
131 		return inquiryRestrictions;
132 	}
133 
134 	@Override
135     public MaintenanceDocumentRestrictions getMaintenanceDocumentRestrictions(
136 			MaintenanceDocument maintenanceDocument, Person user) {
137 
138 		MaintenanceDocumentRestrictions maintenanceDocumentRestrictions = new MaintenanceDocumentRestrictionsBase();
139 		DataObjectEntry dataObjectEntry = getDataDictionaryService()
140 				.getDataDictionary().getDataObjectEntry(
141 						maintenanceDocument.getNewMaintainableObject()
142 								.getDataObject().getClass().getName());
143 		MaintenanceDocumentPresentationController maintenanceDocumentPresentationController = (MaintenanceDocumentPresentationController) getDocumentHelperService()
144 				.getDocumentPresentationController(maintenanceDocument);
145 		MaintenanceDocumentAuthorizer maintenanceDocumentAuthorizer = (MaintenanceDocumentAuthorizer) getDocumentHelperService()
146 				.getDocumentAuthorizer(maintenanceDocument);
147 		considerBusinessObjectFieldUnmaskAuthorization(maintenanceDocument
148 				.getNewMaintainableObject().getDataObject(), user,
149 				maintenanceDocumentRestrictions, "", maintenanceDocument );
150 		considerBusinessObjectFieldViewAuthorization(dataObjectEntry,
151 				maintenanceDocument.getNewMaintainableObject().getDataObject(),
152 				null, user, maintenanceDocumentAuthorizer,
153 				maintenanceDocumentRestrictions, "");
154 		considerBusinessObjectFieldModifyAuthorization(dataObjectEntry,
155 				maintenanceDocument.getNewMaintainableObject().getDataObject(),
156 				null, user, maintenanceDocumentAuthorizer,
157 				maintenanceDocumentRestrictions, "");
158 		considerCustomButtonFieldAuthorization(dataObjectEntry,
159 				maintenanceDocument.getNewMaintainableObject().getDataObject(),
160 				null, user, maintenanceDocumentAuthorizer,
161 				maintenanceDocumentRestrictions, "");
162 		considerInquiryOrMaintenanceDocumentPresentationController(
163 				maintenanceDocumentPresentationController, maintenanceDocument,
164 				maintenanceDocumentRestrictions);
165 		considerInquiryOrMaintenanceDocumentAuthorizer(
166 				maintenanceDocumentAuthorizer, maintenanceDocument, user,
167 				maintenanceDocumentRestrictions);
168 		considerMaintenanceDocumentPresentationController(
169 				maintenanceDocumentPresentationController, maintenanceDocument,
170 				maintenanceDocumentRestrictions);
171 		considerMaintenanceDocumentAuthorizer(maintenanceDocumentAuthorizer,
172 				maintenanceDocument, user, maintenanceDocumentRestrictions);
173 
174 		MaintenanceDocumentEntry maintenanceDocumentEntry = getMaintenanceDocumentDictionaryService().getMaintenanceDocumentEntry(maintenanceDocument
175 				.getDocumentHeader().getWorkflowDocument().getDocumentTypeName());
176 		for (MaintainableSectionDefinition maintainableSectionDefinition : maintenanceDocumentEntry.getMaintainableSections()) {
177 			addMaintainableItemRestrictions(maintainableSectionDefinition.getMaintainableItems(), maintenanceDocumentAuthorizer, maintenanceDocumentRestrictions,
178 					maintenanceDocument, maintenanceDocument.getNewMaintainableObject().getBusinessObject(), "", user);
179 		}
180 		return maintenanceDocumentRestrictions;
181 	}
182 
183 	protected void considerBusinessObjectFieldUnmaskAuthorization(Object dataObject, Person user, BusinessObjectRestrictions businessObjectRestrictions, String propertyPrefix, Document document) {
184 		DataObjectEntry objectEntry = getDataDictionaryService().getDataDictionary().getDataObjectEntry(dataObject.getClass().getName());
185 		for (String attributeName : objectEntry.getAttributeNames()) {
186 			AttributeDefinition attributeDefinition = objectEntry.getAttributeDefinition(attributeName);
187 			if (attributeDefinition.getAttributeSecurity() != null) {
188 				if (attributeDefinition.getAttributeSecurity().isMask() &&
189 						!canFullyUnmaskField(user, dataObject.getClass(), attributeName, document)) {
190 					businessObjectRestrictions.addFullyMaskedField(propertyPrefix + attributeName, attributeDefinition.getAttributeSecurity().getMaskFormatter());
191 				}
192 				if (attributeDefinition.getAttributeSecurity().isPartialMask() &&
193 						!canPartiallyUnmaskField(user, dataObject.getClass(), attributeName, document)) {
194 					businessObjectRestrictions.addPartiallyMaskedField(propertyPrefix + attributeName, attributeDefinition.getAttributeSecurity().getPartialMaskFormatter());
195 				}
196 			}
197 		}
198 	}
199 
200 	/**
201 	 * @param dataObjectEntry if collectionItemBusinessObject is not null, then it is the DD entry for collectionItemBusinessObject.
202 	 * Otherwise, it is the entry for primaryBusinessObject
203 	 * @param primaryDataObject the top-level BO that is being inquiried or maintained
204 	 * @param collectionItemBusinessObject an element of a collection under the primaryBusinessObject that we are evaluating view auths for
205 	 * @param user the logged in user
206 	 * @param businessObjectAuthorizer
207 	 * @param inquiryOrMaintenanceDocumentRestrictions
208 	 * @param propertyPrefix
209 	 */
210 	protected void considerBusinessObjectFieldViewAuthorization(
211 			DataObjectEntry dataObjectEntry,
212 			Object primaryDataObject,
213 			BusinessObject collectionItemBusinessObject,
214 			Person user,
215 			BusinessObjectAuthorizer businessObjectAuthorizer,
216 			InquiryOrMaintenanceDocumentRestrictions inquiryOrMaintenanceDocumentRestrictions,
217 			String propertyPrefix) {
218 		for (String attributeName : dataObjectEntry.getAttributeNames()) {
219 			AttributeDefinition attributeDefinition = dataObjectEntry
220 					.getAttributeDefinition(attributeName);
221 			if (attributeDefinition.getAttributeSecurity() != null) {
222 				if (attributeDefinition.getAttributeSecurity().isHide()) {
223 					Map<String, String> collectionItemPermissionDetails = new HashMap<String, String>();
224 					Map<String, String> collectionItemRoleQualifications = null;
225 					if (ObjectUtils.isNotNull(collectionItemBusinessObject)) {
226 						collectionItemPermissionDetails.putAll(getFieldPermissionDetails(collectionItemBusinessObject, attributeName));
227 						collectionItemPermissionDetails.putAll(businessObjectAuthorizer.
228 								getCollectionItemPermissionDetails(collectionItemBusinessObject));
229 						collectionItemRoleQualifications = new HashMap<String, String>(businessObjectAuthorizer.
230 								getCollectionItemRoleQualifications(collectionItemBusinessObject));
231 					}
232 					else {
233 						collectionItemPermissionDetails.putAll(getFieldPermissionDetails(primaryDataObject, attributeName));
234 					}
235 					if (!businessObjectAuthorizer
236 							.isAuthorizedByTemplate(
237 									primaryDataObject,
238 									KRADConstants.KNS_NAMESPACE,
239 									KimConstants.PermissionTemplateNames.VIEW_MAINTENANCE_INQUIRY_FIELD,
240 									user.getPrincipalId(),
241 									collectionItemPermissionDetails,
242 									collectionItemRoleQualifications)) {
243 						inquiryOrMaintenanceDocumentRestrictions
244 								.addHiddenField(propertyPrefix + attributeName);
245 					}
246 				}
247 			}
248 		}
249 	}
250 
251 	/**
252 	 * @param dataObjectEntry if collectionItemBusinessObject is not null, then it is the DD entry for collectionItemBusinessObject.
253 	 * Otherwise, it is the entry for primaryBusinessObject
254 	 * @param primaryDataObject the top-level BO that is being inquiried or maintained
255 	 * @param collectionItemBusinessObject an element of a collection under the primaryBusinessObject that we are evaluating view auths for
256 	 * @param user the logged in user
257 	 * @param businessObjectAuthorizer
258 	 * @param inquiryOrMaintenanceDocumentRestrictions
259 	 * @param propertyPrefix
260 	 */
261 	protected void considerBusinessObjectFieldModifyAuthorization(
262 			DataObjectEntry dataObjectEntry,
263 			Object primaryDataObject,
264 			BusinessObject collectionItemBusinessObject, Person user,
265 			BusinessObjectAuthorizer businessObjectAuthorizer,
266 			MaintenanceDocumentRestrictions maintenanceDocumentRestrictions,
267 			String propertyPrefix) {
268 		for (String attributeName : dataObjectEntry.getAttributeNames()) {
269 			AttributeDefinition attributeDefinition = dataObjectEntry
270 					.getAttributeDefinition(attributeName);
271 			if (attributeDefinition.getAttributeSecurity() != null) {
272 				Map<String, String> collectionItemPermissionDetails = new HashMap<String, String>();
273 				Map<String, String> collectionItemRoleQualifications = null;
274 				if (ObjectUtils.isNotNull(collectionItemBusinessObject)) {
275 					collectionItemPermissionDetails.putAll(getFieldPermissionDetails(collectionItemBusinessObject, attributeName));
276 					collectionItemPermissionDetails.putAll(businessObjectAuthorizer.
277 							getCollectionItemPermissionDetails(collectionItemBusinessObject));
278 					collectionItemRoleQualifications = new HashMap<String, String>(businessObjectAuthorizer.
279 							getCollectionItemRoleQualifications(collectionItemBusinessObject));
280 				}
281 				else {
282 					collectionItemPermissionDetails.putAll(getFieldPermissionDetails(primaryDataObject, attributeName));
283 				}
284 				if (attributeDefinition.getAttributeSecurity().isReadOnly()) {
285 					if (!businessObjectAuthorizer
286 								.isAuthorizedByTemplate(
287 										primaryDataObject,
288 										KRADConstants.KNS_NAMESPACE,
289 										KimConstants.PermissionTemplateNames.MODIFY_FIELD,
290 										user.getPrincipalId(),
291 										collectionItemPermissionDetails,
292 										collectionItemRoleQualifications)) {
293 						maintenanceDocumentRestrictions
294 								.addReadOnlyField(propertyPrefix + attributeName);
295 					}
296 				}
297 			}
298 		}
299 	}
300 
301 	/**
302 	 * @param dataObjectEntry if collectionItemBusinessObject is not null, then it is the DD entry for collectionItemBusinessObject.
303 	 * Otherwise, it is the entry for primaryBusinessObject
304 	 * @param primaryDataObject the top-level BO that is being inquiried or maintained
305 	 * @param collectionItemBusinessObject an element of a collection under the primaryBusinessObject that we are evaluating view auths for
306 	 * @param user the logged in user
307 	 * @param businessObjectAuthorizer
308 	 * @param inquiryOrMaintenanceDocumentRestrictions
309 	 * @param propertyPrefix
310 	 */
311 	protected void considerCustomButtonFieldAuthorization(
312 			DataObjectEntry dataObjectEntry,
313 			Object primaryDataObject,
314 			BusinessObject collectionItemBusinessObject,
315 			Person user,
316 			BusinessObjectAuthorizer businessObjectAuthorizer,
317 			MaintenanceDocumentRestrictions maintenanceDocumentRestrictions,
318 			String propertyPrefix) {
319 		for (String attributeName : dataObjectEntry.getAttributeNames()) {
320 			AttributeDefinition attributeDefinition = dataObjectEntry
321 					.getAttributeDefinition(attributeName);
322 			// TODO what is the equivalent of control.isButton in KRAD
323 			if (attributeDefinition.getControl() != null &&
324 			        attributeDefinition.getControl().isButton()) {
325 				Map<String, String> collectionItemPermissionDetails = new HashMap<String, String>();
326 				Map<String, String> collectionItemRoleQualifications = null;
327 				if (ObjectUtils.isNotNull(collectionItemBusinessObject)) {
328 					collectionItemPermissionDetails.putAll(getButtonFieldPermissionDetails(collectionItemBusinessObject, attributeName));
329 					collectionItemPermissionDetails.putAll(businessObjectAuthorizer.
330 							getCollectionItemPermissionDetails(collectionItemBusinessObject));
331 					collectionItemRoleQualifications = new HashMap<String, String>(businessObjectAuthorizer.
332 							getCollectionItemRoleQualifications(collectionItemBusinessObject));
333 				}
334 				else {
335 					getButtonFieldPermissionDetails(primaryDataObject, attributeName);
336 				}
337 
338 				if (!businessObjectAuthorizer
339 						.isAuthorizedByTemplate(
340 								primaryDataObject,
341 								KRADConstants.KNS_NAMESPACE,
342 								KimConstants.PermissionTemplateNames.PERFORM_CUSTOM_MAINTENANCE_DOCUMENT_FUNCTION,
343 								user.getPrincipalId(),
344 								collectionItemPermissionDetails,
345 								collectionItemRoleQualifications)) {
346 					maintenanceDocumentRestrictions
347 							.addHiddenField(propertyPrefix + attributeName);
348 				}
349 			}
350 		}
351 	}
352 
353 	protected void considerInquiryOrMaintenanceDocumentPresentationController(
354 			InquiryOrMaintenanceDocumentPresentationController businessObjectPresentationController,
355 			Object businessObject,
356 			InquiryOrMaintenanceDocumentRestrictions inquiryOrMaintenanceDocumentRestrictions) {
357 		for (String attributeName : businessObjectPresentationController
358 				.getConditionallyHiddenPropertyNames(businessObject)) {
359 			inquiryOrMaintenanceDocumentRestrictions
360 					.addHiddenField(attributeName);
361 		}
362 		for (String sectionId : businessObjectPresentationController
363 				.getConditionallyHiddenSectionIds(businessObject)) {
364 			inquiryOrMaintenanceDocumentRestrictions
365 					.addHiddenSectionId(sectionId);
366 		}
367 	}
368 
369 	protected void considerInquiryOrMaintenanceDocumentAuthorizer(
370 			InquiryOrMaintenanceDocumentAuthorizer authorizer,
371 			Object businessObject, Person user,
372 			InquiryOrMaintenanceDocumentRestrictions restrictions) {
373 		for (String sectionId : authorizer
374 				.getSecurePotentiallyHiddenSectionIds()) {
375 			Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
376 			additionalPermissionDetails
377 					.put(KimConstants.AttributeConstants.SECTION_ID, sectionId);
378 			if (!authorizer.isAuthorizedByTemplate(businessObject,
379 					KRADConstants.KNS_NAMESPACE,
380 					KimConstants.PermissionTemplateNames.VIEW_SECTION, user
381 							.getPrincipalId(), additionalPermissionDetails,
382 					null)) {
383 				restrictions.addHiddenSectionId(sectionId);
384 			}
385 		}
386 	}
387 
388 	protected void considerMaintenanceDocumentPresentationController(
389 			MaintenanceDocumentPresentationController presentationController,
390 			MaintenanceDocument document,
391 			MaintenanceDocumentRestrictions restrictions) {
392 		for (String attributeName : presentationController
393 				.getConditionallyReadOnlyPropertyNames(document)) {
394 			restrictions.addReadOnlyField(attributeName);
395 		}
396 		for (String sectionId : presentationController
397 				.getConditionallyReadOnlySectionIds(document)) {
398 			restrictions.addReadOnlySectionId(sectionId);
399 		}
400 	}
401 
402 	protected void considerMaintenanceDocumentAuthorizer(
403 			MaintenanceDocumentAuthorizer authorizer,
404 			MaintenanceDocument document, Person user,
405 			MaintenanceDocumentRestrictions restrictions) {
406 		for (String sectionId : authorizer
407 				.getSecurePotentiallyReadOnlySectionIds()) {
408 			Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
409 			additionalPermissionDetails
410 					.put(KimConstants.AttributeConstants.SECTION_ID, sectionId);
411 			if (!authorizer.isAuthorizedByTemplate(document,
412 					KRADConstants.KNS_NAMESPACE,
413 					KimConstants.PermissionTemplateNames.MODIFY_SECTION, user
414 							.getPrincipalId(), additionalPermissionDetails,
415 					null)) {
416 				restrictions.addReadOnlySectionId(sectionId);
417 			}
418 		}
419 	}
420 
421 	@SuppressWarnings("rawtypes")
422     protected void addInquirableItemRestrictions(Collection sectionDefinitions,
423 			InquiryAuthorizer authorizer, InquiryRestrictions restrictions,
424 			BusinessObject primaryBusinessObject,
425 			BusinessObject businessObject, String propertyPrefix, Person user) {
426 		for (Object inquirableItemDefinition : sectionDefinitions) {
427 			if (inquirableItemDefinition instanceof InquiryCollectionDefinition) {
428 				InquiryCollectionDefinition inquiryCollectionDefinition = (InquiryCollectionDefinition) inquirableItemDefinition;
429 				BusinessObjectEntry collectionBusinessObjectEntry = (BusinessObjectEntry) getDataDictionaryService()
430 						.getDataDictionary().getBusinessObjectEntry(
431 								inquiryCollectionDefinition.getBusinessObjectClass().getName());
432 
433 				try {
434 					Collection<?> collection = (Collection<?>) PropertyUtils
435 							.getProperty(businessObject,
436 									inquiryCollectionDefinition.getName());
437 					int i = 0;
438 					for (Iterator<?> iterator = collection.iterator(); iterator.hasNext();) {
439 						String newPropertyPrefix = propertyPrefix + inquiryCollectionDefinition.getName() + "[" + i + "].";
440 						Object collectionItemBusinessObject = iterator.next();
441 						considerBusinessObjectFieldUnmaskAuthorization(
442 								collectionItemBusinessObject, user, restrictions,
443 								newPropertyPrefix, null);
444 						if ( collectionItemBusinessObject instanceof BusinessObject ) {
445     						considerBusinessObjectFieldViewAuthorization(
446     								collectionBusinessObjectEntry, primaryBusinessObject, (BusinessObject)collectionItemBusinessObject,
447     								user, authorizer, restrictions, newPropertyPrefix);
448     						addInquirableItemRestrictions(
449     								inquiryCollectionDefinition
450     										.getInquiryCollections(),
451     								authorizer,
452     								restrictions,
453     								primaryBusinessObject,
454     								(BusinessObject)collectionItemBusinessObject,
455     								newPropertyPrefix,
456     								user);
457 						}
458 						i++;
459 					}
460 				} catch (Exception e) {
461 					throw new RuntimeException(
462 							"Unable to resolve collection property: "
463 									+ businessObject.getClass() + ":"
464 									+ inquiryCollectionDefinition.getName(), e);
465 				}
466 			}
467 		}
468 	}
469 
470 	@SuppressWarnings("unchecked")
471 	protected void addMaintainableItemRestrictions(List<? extends MaintainableItemDefinition> itemDefinitions,
472 			MaintenanceDocumentAuthorizer authorizer,
473 			MaintenanceDocumentRestrictions restrictions,
474 			MaintenanceDocument maintenanceDocument,
475 			BusinessObject businessObject, String propertyPrefix, Person user) {
476 		for (MaintainableItemDefinition maintainableItemDefinition : itemDefinitions) {
477 			if (maintainableItemDefinition instanceof MaintainableCollectionDefinition) {
478 				try {
479 					MaintainableCollectionDefinition maintainableCollectionDefinition = (MaintainableCollectionDefinition) maintainableItemDefinition;
480 
481 					Collection<BusinessObject> collection = (Collection<BusinessObject>) ObjectUtils
482 							.getNestedValue(businessObject,
483 									maintainableItemDefinition.getName());
484 					BusinessObjectEntry collectionBusinessObjectEntry = (BusinessObjectEntry) getDataDictionaryService()
485 							.getDataDictionary().getBusinessObjectEntry(
486 									maintainableCollectionDefinition.getBusinessObjectClass().getName());
487 					if (CollectionUtils.isNotEmpty(collection)) {
488                     //if (collection != null && !collection.isEmpty()) {
489 				    	int i = 0;
490 			     		for (Iterator<BusinessObject> iterator = collection.iterator(); iterator
491 							.hasNext();) {
492 			     			String newPropertyPrefix = propertyPrefix + maintainableItemDefinition.getName() + "[" + i + "].";
493 					    	BusinessObject collectionBusinessObject = iterator.next();
494 					    	considerBusinessObjectFieldUnmaskAuthorization(
495 								collectionBusinessObject, user, restrictions,
496 								newPropertyPrefix, maintenanceDocument);
497 					    	considerBusinessObjectFieldViewAuthorization(
498 								collectionBusinessObjectEntry, maintenanceDocument, collectionBusinessObject, user,
499 								authorizer, restrictions, newPropertyPrefix);
500 					    	considerBusinessObjectFieldModifyAuthorization(
501 								collectionBusinessObjectEntry, maintenanceDocument, collectionBusinessObject, user,
502 								authorizer, restrictions, newPropertyPrefix);
503 					    	addMaintainableItemRestrictions(
504 								((MaintainableCollectionDefinition) maintainableItemDefinition)
505 										.getMaintainableCollections(),
506 								authorizer, restrictions, maintenanceDocument,
507 								collectionBusinessObject, newPropertyPrefix,
508 								user);
509 				     		addMaintainableItemRestrictions(
510 								((MaintainableCollectionDefinition) maintainableItemDefinition)
511 										.getMaintainableFields(), authorizer,
512 								restrictions, maintenanceDocument,
513 								collectionBusinessObject, newPropertyPrefix,
514 								user);
515 					    	i++;
516 				    	}
517 					}
518 				} catch (Exception e) {
519 					throw new RuntimeException(
520 							"Unable to resolve collection property: "
521 									+ businessObject.getClass() + ":"
522 									+ maintainableItemDefinition.getName(), e);
523 				}
524 			}
525 		}
526 	}
527 
528 	@Override
529     public boolean canFullyUnmaskField(Person user,
530 			Class<?> dataObjectClass, String fieldName, Document document) {
531 		// KFSMI-5095
532 		if(isNonProductionEnvAndUnmaskingTurnedOff()) {
533             return false;
534         }
535 
536 		if(user==null || StringUtils.isEmpty(user.getPrincipalId())) {
537             return false;
538         }
539 		Boolean result = null;
540 		if (document != null) { // if a document was passed, evaluate the permission in the context of a document
541 			try { // try/catch and fallthrough is a fix for KULRICE-3365
542 				result = getDocumentHelperService().getDocumentAuthorizer( document )
543 				.isAuthorizedByTemplate( document,
544 						KRADConstants.KNS_NAMESPACE,
545 						KimConstants.PermissionTemplateNames.FULL_UNMASK_FIELD,
546 						user.getPrincipalId(), getFieldPermissionDetails(dataObjectClass, fieldName), null  );
547 			} catch (IllegalArgumentException e) {
548 				// document didn't have needed metadata
549 				// TODO: this requires intimate knowledge of DocumentHelperServiceImpl
550 			}
551 		}
552 		if (result == null) {
553 			result = getPermissionService().isAuthorizedByTemplate(user.getPrincipalId(), KRADConstants.KNS_NAMESPACE,
554                     KimConstants.PermissionTemplateNames.FULL_UNMASK_FIELD, new HashMap<String, String>(
555                     getFieldPermissionDetails(dataObjectClass, fieldName)), Collections.<String, String>emptyMap());
556 		}
557 		return result; // should be safe to return Boolean here since the only circumstances that
558 		               // will leave it null will result in an exception being thrown above.
559 	}
560 
561 	@Override
562     public boolean canPartiallyUnmaskField(
563 			Person user, Class<?> dataObjectClass, String fieldName, Document document) {
564 		// KFSMI-5095
565 		if(isNonProductionEnvAndUnmaskingTurnedOff()) {
566             return false;
567         }
568 
569 		if(user==null || StringUtils.isEmpty(user.getPrincipalId())) {
570             return false;
571         }
572 
573 		if ( document == null ) {
574 			return getPermissionService().isAuthorizedByTemplate(user.getPrincipalId(), KRADConstants.KNS_NAMESPACE,
575                     KimConstants.PermissionTemplateNames.PARTIAL_UNMASK_FIELD, new HashMap<String, String>(
576                     getFieldPermissionDetails(dataObjectClass, fieldName)), Collections.<String, String>emptyMap());
577 		} else { // if a document was passed, evaluate the permission in the context of a document
578 			return getDocumentHelperService().getDocumentAuthorizer( document )
579 					.isAuthorizedByTemplate( document,
580 											 KRADConstants.KNS_NAMESPACE,
581 											 KimConstants.PermissionTemplateNames.PARTIAL_UNMASK_FIELD,
582 											 user.getPrincipalId(), getFieldPermissionDetails(dataObjectClass, fieldName), Collections.<String, String>emptyMap()  );
583 		}
584 	}
585 
586 	protected Map<String, String> getFieldPermissionDetails(
587 			Class<?> dataObjectClass, String attributeName) {
588 		try {
589 			return getFieldPermissionDetails(dataObjectClass.newInstance(),
590 					attributeName);
591 		} catch (Exception e) {
592 			throw new RuntimeException(
593 					"The getPermissionDetails method of BusinessObjectAuthorizationServiceImpl was unable to instantiate the dataObjectClass"
594 							+ dataObjectClass, e);
595 		}
596 	}
597 
598 	protected Map<String, String> getFieldPermissionDetails(
599 			Object dataObject, String attributeName) {
600 		Map<String, String> permissionDetails = null;
601 		String namespaceCode = null;
602 		String componentName = null;
603 		String propertyName = null;
604 		// JHK: commenting out for KFSMI-2398 - permission checks need to be done at the level specified
605 		// that is, if the parent object specifies the security, that object should be used for the
606 		// component
607 //		if (attributeName.contains(".")) {
608 //			try {
609 //				permissionDetails = KimCommonUtils
610 //						.getNamespaceAndComponentSimpleName(PropertyUtils
611 //								.getPropertyType(businessObject, attributeName
612 //										.substring(0, attributeName
613 //												.lastIndexOf("."))));
614 //			} catch (Exception e) {
615 //				throw new RuntimeException(
616 //						"Unable to discover nested business object class: "
617 //								+ businessObject.getClass() + " : "
618 //								+ attributeName, e);
619 //			}
620 
621 //			permissionDetails.put(KimAttributes.PROPERTY_NAME, attributeName
622 //					.substring(attributeName.indexOf(".") + 1));
623 //		} else {
624 			permissionDetails = KRADUtils
625 					.getNamespaceAndComponentSimpleName(dataObject.getClass());
626 			permissionDetails.put(KimConstants.AttributeConstants.PROPERTY_NAME, attributeName);
627 //		}
628 		return permissionDetails;
629 	}
630 
631 	protected Map<String, String> getButtonFieldPermissionDetails(
632 			Object businessObject, String attributeName) {
633 		Map<String, String> permissionDetails = new HashMap<String, String>();
634 		if (attributeName.contains(".")) {
635 			permissionDetails.put(KimConstants.AttributeConstants.BUTTON_NAME, attributeName);
636 		} else {
637 			permissionDetails.put(KimConstants.AttributeConstants.BUTTON_NAME, attributeName);
638 		}
639 		return permissionDetails;
640 	}
641 
642 	private PermissionService getPermissionService() {
643 		if (permissionService == null) {
644 			permissionService = KimApiServiceLocator
645 					.getPermissionService();
646 		}
647 		return permissionService;
648 	}
649 
650 	private BusinessObjectDictionaryService getBusinessObjectDictionaryService() {
651 		if (businessObjectDictionaryService == null) {
652 			businessObjectDictionaryService = KNSServiceLocator
653 					.getBusinessObjectDictionaryService();
654 		}
655 		return businessObjectDictionaryService;
656 	}
657 
658 	private MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() {
659 		if (maintenanceDocumentDictionaryService == null) {
660 			maintenanceDocumentDictionaryService = KNSServiceLocator
661 					.getMaintenanceDocumentDictionaryService();
662 		}
663 		return maintenanceDocumentDictionaryService;
664 	}
665 
666 	private ConfigurationService getKualiConfigurationService() {
667 		if (kualiConfigurationService == null) {
668 			kualiConfigurationService = CoreApiServiceLocator.getKualiConfigurationService();
669 		}
670 		return kualiConfigurationService;
671 	}
672 
673 	private boolean isNonProductionEnvAndUnmaskingTurnedOff(){
674 		return !getKualiConfigurationService().getPropertyValueAsString(KRADConstants.PROD_ENVIRONMENT_CODE_KEY)
675                 .equalsIgnoreCase(
676                         getKualiConfigurationService().getPropertyValueAsString(KRADConstants.ENVIRONMENT_KEY)) &&
677 				!getKualiConfigurationService().getPropertyValueAsBoolean(KRADConstants.ENABLE_NONPRODUCTION_UNMASKING);
678 	}
679 
680     protected DocumentHelperService getDocumentHelperService() {
681         return KNSServiceLocator.getDocumentHelperService();
682     }
683 
684 }