View Javadoc

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