View Javadoc
1   /**
2    * Copyright 2005-2014 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.krad.uif.view;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.CoreApiServiceLocator;
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.krad.bo.DataObjectAuthorizerBase;
24  import org.kuali.rice.krad.datadictionary.AttributeSecurity;
25  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
26  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
27  import org.kuali.rice.krad.uif.component.Component;
28  import org.kuali.rice.krad.uif.component.ComponentSecurity;
29  import org.kuali.rice.krad.uif.component.DataBinding;
30  import org.kuali.rice.krad.uif.container.CollectionGroup;
31  import org.kuali.rice.krad.uif.container.Group;
32  import org.kuali.rice.krad.uif.element.Action;
33  import org.kuali.rice.krad.uif.field.DataField;
34  import org.kuali.rice.krad.uif.field.DataFieldSecurity;
35  import org.kuali.rice.krad.uif.field.Field;
36  import org.kuali.rice.krad.uif.field.FieldSecurity;
37  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
38  import org.kuali.rice.krad.uif.widget.Widget;
39  import org.kuali.rice.krad.util.KRADConstants;
40  import org.kuali.rice.krad.util.KRADUtils;
41  
42  import java.util.HashMap;
43  import java.util.HashSet;
44  import java.util.Map;
45  import java.util.Set;
46  
47  /**
48   * Implementation of {@link ViewAuthorizer} that verifies authorization with KIM permission checks
49   *
50   * <p>
51   * Each permission goes through one of the isAuthorized methods provided by
52   * {@link org.kuali.rice.krad.bo.DataObjectAuthorizer}, these in turn call {@link #addPermissionDetails(Object, java.util.Map)}
53   * and {@link #addRoleQualification(Object, java.util.Map)} for building the permission and role maps to send with
54   * the permission check. Subclasses can override these methods to add additional attributes
55   * </p>
56   *
57   * @author Kuali Rice Team (rice.collab@kuali.org)
58   */
59  @BeanTag(name = "viewAuthorizer-bean")
60  public class ViewAuthorizerBase extends DataObjectAuthorizerBase implements ViewAuthorizer {
61      private static final long serialVersionUID = -2687378084630965412L;
62      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ViewAuthorizerBase.class);
63  
64      private ConfigurationService configurationService;
65  
66      /**
67       * @see ViewAuthorizer#getActionFlags(org.kuali.rice.krad.uif.view.View, org.kuali.rice.krad.uif.view.ViewModel,
68       *      org.kuali.rice.kim.api.identity.Person, java.util.Set<java.lang.String>)
69       */
70      public Set<String> getActionFlags(View view, ViewModel model, Person user, Set<String> actions) {
71          if (actions.contains(KRADConstants.KUALI_ACTION_CAN_EDIT) && !canEditView(view, model, user)) {
72              actions.remove(KRADConstants.KUALI_ACTION_CAN_EDIT);
73          }
74  
75          return actions;
76      }
77  
78      /**
79       * @see ViewAuthorizer#getEditModes(org.kuali.rice.krad.uif.view.View, org.kuali.rice.krad.uif.view.ViewModel,
80       *      org.kuali.rice.kim.api.identity.Person, java.util.Set<java.lang.String>)
81       */
82      public Set<String> getEditModes(View view, ViewModel model, Person user, Set<String> editModes) {
83          Set<String> unauthorizedEditModes = new HashSet<String>();
84  
85          Object dataObjectForContext = getDataObjectContext(view, model);
86  
87          // loop through supplied editModes and make sure KIM permission exists
88          for (String editMode : editModes) {
89              Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
90              additionalPermissionDetails.put(KimConstants.AttributeConstants.EDIT_MODE, editMode);
91              additionalPermissionDetails.put(KimConstants.AttributeConstants.VIEW_ID, view.getId());
92              boolean exists = permissionExistsByTemplate(dataObjectForContext, KRADConstants.KRAD_NAMESPACE,
93                      KimConstants.PermissionTemplateNames.USE_VIEW, additionalPermissionDetails);
94              if (exists) {
95                  boolean authorized = isAuthorizedByTemplate(dataObjectForContext, KRADConstants.KRAD_NAMESPACE,
96                          KimConstants.PermissionTemplateNames.USE_VIEW, user.getPrincipalId(),
97                          additionalPermissionDetails, null);
98                  if (!authorized) {
99                      unauthorizedEditModes.add(editMode);
100                 }
101             }
102         }
103         editModes.removeAll(unauthorizedEditModes);
104 
105         return editModes;
106     }
107 
108     /**
109      * Checks for an open view permission for the view id, and if found verifies the user has that permission
110      *
111      * @see ViewAuthorizer#canOpenView(View, ViewModel, org.kuali.rice.kim.api.identity.Person)
112      */
113     public boolean canOpenView(View view, ViewModel model, Person user) {
114         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
115         additionalPermissionDetails.put(KimConstants.AttributeConstants.NAMESPACE_CODE, view.getNamespaceCode());
116         additionalPermissionDetails.put(KimConstants.AttributeConstants.VIEW_ID, model.getViewId());
117 
118         if (permissionExistsByTemplate(model, KRADConstants.KRAD_NAMESPACE,
119                 KimConstants.PermissionTemplateNames.OPEN_VIEW, additionalPermissionDetails)) {
120             return isAuthorizedByTemplate(model, KRADConstants.KRAD_NAMESPACE,
121                     KimConstants.PermissionTemplateNames.OPEN_VIEW, user.getPrincipalId(), additionalPermissionDetails,
122                     null);
123         }
124 
125         return true;
126     }
127 
128     /**
129      * Checks for an edit view permission for the view id, and if found verifies the user has that permission
130      *
131      * @see ViewAuthorizer#canEditView(org.kuali.rice.krad.uif.view.View, org.kuali.rice.krad.uif.view.ViewModel,
132      *      org.kuali.rice.kim.api.identity.Person)
133      */
134     public boolean canEditView(View view, ViewModel model, Person user) {
135         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
136         additionalPermissionDetails.put(KimConstants.AttributeConstants.NAMESPACE_CODE, view.getNamespaceCode());
137         additionalPermissionDetails.put(KimConstants.AttributeConstants.VIEW_ID, model.getViewId());
138 
139         if (permissionExistsByTemplate(model, KRADConstants.KRAD_NAMESPACE,
140                 KimConstants.PermissionTemplateNames.EDIT_VIEW, additionalPermissionDetails)) {
141             return isAuthorizedByTemplate(model, KRADConstants.KRAD_NAMESPACE,
142                     KimConstants.PermissionTemplateNames.EDIT_VIEW, user.getPrincipalId(), additionalPermissionDetails,
143                     null);
144         }
145 
146         return true;
147     }
148 
149     /**
150      * @see ViewAuthorizer#canUnmaskField(org.kuali.rice.krad.uif.view.View, org.kuali.rice.krad.uif.view.ViewModel,
151      * org.kuali.rice.krad.uif.field.DataField, java.lang.String, org.kuali.rice.kim.api.identity.Person)
152      */
153     public boolean canUnmaskField(View view, ViewModel model, DataField field, String propertyName, Person user) {
154         if (field.getDataFieldSecurity() == null) {
155             return true;
156         }
157 
158         // check mask authz flag is set
159         AttributeSecurity attributeSecurity = field.getDataFieldSecurity().getAttributeSecurity();
160         if (attributeSecurity == null || !attributeSecurity.isMask()) {
161             return true;
162         }
163 
164         // for non-production environments the ability to unmask can be disabled by a system parameter
165         if (isNonProductionEnvAndUnmaskingTurnedOff()) {
166             return false;
167         }
168 
169         Object dataObjectForContext = getDataObjectContext(view, model);
170 
171         Map<String, String> permissionDetails = new HashMap<String, String>();
172         permissionDetails = KRADUtils.getNamespaceAndComponentSimpleName(dataObjectForContext.getClass());
173         permissionDetails.put(KimConstants.AttributeConstants.PROPERTY_NAME, propertyName);
174         // TODO: check for namespace, component, attribute override on attribute security
175 
176         if (field.getComponentSecurity().getAdditionalPermissionDetails() != null) {
177             permissionDetails.putAll(field.getComponentSecurity().getAdditionalPermissionDetails());
178         }
179 
180         Map<String, String> roleQualifications = new HashMap<String, String>();
181         if (field.getComponentSecurity().getAdditionalRoleQualifiers() != null) {
182             roleQualifications.putAll(field.getComponentSecurity().getAdditionalRoleQualifiers());
183         }
184 
185         return isAuthorizedByTemplate(dataObjectForContext, KRADConstants.KNS_NAMESPACE,
186                 KimConstants.PermissionTemplateNames.FULL_UNMASK_FIELD, user.getPrincipalId(), permissionDetails,
187                 roleQualifications);
188     }
189 
190     /**
191      * @see ViewAuthorizer#canPartialUnmaskField(org.kuali.rice.krad.uif.view.View, org.kuali.rice.krad.uif.view.ViewModel,
192      * org.kuali.rice.krad.uif.field.DataField, java.lang.String, org.kuali.rice.kim.api.identity.Person)
193      */
194     public boolean canPartialUnmaskField(View view, ViewModel model, DataField field, String propertyName,
195             Person user) {
196         if (field.getDataFieldSecurity() == null) {
197             return true;
198         }
199 
200         // check partial mask authz flag is set
201         AttributeSecurity attributeSecurity = field.getDataFieldSecurity().getAttributeSecurity();
202         if (attributeSecurity == null || !attributeSecurity.isPartialMask()) {
203             return true;
204         }
205 
206         // for non-production environments the ability to unmask can be disabled by a system parameter
207         if (isNonProductionEnvAndUnmaskingTurnedOff()) {
208             return false;
209         }
210 
211         Object dataObjectForContext = getDataObjectContext(view, model);
212 
213         Map<String, String> permissionDetails = new HashMap<String, String>();
214         permissionDetails = KRADUtils.getNamespaceAndComponentSimpleName(dataObjectForContext.getClass());
215         permissionDetails.put(KimConstants.AttributeConstants.PROPERTY_NAME, propertyName);
216         // TODO: check for namespace, component, attribute override on attribute security
217 
218         if (field.getComponentSecurity().getAdditionalPermissionDetails() != null) {
219             permissionDetails.putAll(field.getComponentSecurity().getAdditionalPermissionDetails());
220         }
221 
222         Map<String, String> roleQualifications = new HashMap<String, String>();
223         if (field.getComponentSecurity().getAdditionalRoleQualifiers() != null) {
224             roleQualifications.putAll(field.getComponentSecurity().getAdditionalRoleQualifiers());
225         }
226 
227         return isAuthorizedByTemplate(dataObjectForContext, KRADConstants.KNS_NAMESPACE,
228                 KimConstants.PermissionTemplateNames.PARTIAL_UNMASK_FIELD, user.getPrincipalId(), permissionDetails,
229                 roleQualifications);
230     }
231 
232     /**
233      * @see ViewAuthorizer#canEditField(org.kuali.rice.krad.uif.view.View, org.kuali.rice.krad.uif.view.ViewModel,
234      * org.kuali.rice.krad.uif.field.Field, java.lang.String, org.kuali.rice.kim.api.identity.Person)
235      */
236     public boolean canEditField(View view, ViewModel model, Field field, String propertyName, Person user) {
237         ComponentSecurity componentSecurity = field.getComponentSecurity();
238 
239         // check component security exists
240         if (componentSecurity == null) {
241             return true;
242         }
243 
244         // first check hide flag is set (lower precedence)
245         if (componentSecurity.isEditAuthz() == null && !isDataFieldAttributeSecurityHide(field)) {
246             return true;
247         }
248 
249         // then check edit authz is set (higher precedence)
250         if (componentSecurity.isEditAuthz() != null && !componentSecurity.isEditAuthz().booleanValue()) {
251             return true;
252         }
253 
254         return isAuthorizedByTemplate(view, field, model, KimConstants.PermissionTemplateNames.EDIT_FIELD, user, null,
255                 null, false);
256     }
257 
258     /**
259      * @see ViewAuthorizer#canViewField(org.kuali.rice.krad.uif.view.View, org.kuali.rice.krad.uif.view.ViewModel,
260      * org.kuali.rice.krad.uif.field.Field, java.lang.String, org.kuali.rice.kim.api.identity.Person)
261      */
262     public boolean canViewField(View view, ViewModel model, Field field, String propertyName, Person user) {
263         ComponentSecurity componentSecurity = field.getComponentSecurity();
264 
265         // check component security exists
266         if (componentSecurity == null) {
267             return true;
268         }
269 
270         // first check hide flag is set (lower precedence)
271         if (componentSecurity.isViewAuthz() == null && !isDataFieldAttributeSecurityHide(field)) {
272             return true;
273         }
274 
275         // then check view authz is set (higher precedence)
276         if (componentSecurity.isViewAuthz() != null && !componentSecurity.isViewAuthz().booleanValue()) {
277             return true;
278         }
279 
280         return isAuthorizedByTemplate(view, field, model, KimConstants.PermissionTemplateNames.VIEW_FIELD, user, null,
281                 null, false);
282     }
283 
284     /**
285      * @see ViewAuthorizer#canEditGroup(org.kuali.rice.krad.uif.view.View, org.kuali.rice.krad.uif.view.ViewModel,
286      * org.kuali.rice.krad.uif.container.Group, java.lang.String, org.kuali.rice.kim.api.identity.Person)
287      */
288     public boolean canEditGroup(View view, ViewModel model, Group group, String groupId, Person user) {
289         ComponentSecurity componentSecurity = group.getComponentSecurity();
290 
291         // check component security exists
292         if (componentSecurity == null) {
293             return true;
294         }
295 
296         // check edit group authz flag is set
297         if (componentSecurity.isEditAuthz() == null || !componentSecurity.isEditAuthz().booleanValue()) {
298             return true;
299         }
300 
301         return isAuthorizedByTemplate(view, group, model, KimConstants.PermissionTemplateNames.EDIT_GROUP, user, null,
302                 null, false);
303     }
304 
305     /**
306      * @see ViewAuthorizer#canViewGroup(org.kuali.rice.krad.uif.view.View, org.kuali.rice.krad.uif.view.ViewModel,
307      * org.kuali.rice.krad.uif.container.Group, java.lang.String, org.kuali.rice.kim.api.identity.Person)
308      */
309     public boolean canViewGroup(View view, ViewModel model, Group group, String groupId, Person user) {
310         ComponentSecurity componentSecurity = group.getComponentSecurity();
311 
312         // check component security exists
313         if (componentSecurity == null) {
314             return true;
315         }
316 
317         // check view group authz flag is set
318         if (componentSecurity.isViewAuthz() == null || !componentSecurity.isViewAuthz().booleanValue()) {
319             return true;
320         }
321 
322         return isAuthorizedByTemplate(view, group, model, KimConstants.PermissionTemplateNames.VIEW_GROUP, user, null,
323                 null, false);
324     }
325 
326     /**
327      * @see ViewAuthorizer#canEditWidget(org.kuali.rice.krad.uif.view.View, org.kuali.rice.krad.uif.view.ViewModel,
328      * org.kuali.rice.krad.uif.widget.Widget, java.lang.String, org.kuali.rice.kim.api.identity.Person)
329      */
330     public boolean canEditWidget(View view, ViewModel model, Widget widget, String widgetId, Person user) {
331         ComponentSecurity componentSecurity = widget.getComponentSecurity();
332 
333         // check component security exists
334         if (componentSecurity == null) {
335             return true;
336         }
337 
338         // check edit widget authz flag is set
339         if (componentSecurity.isEditAuthz() == null || !componentSecurity.isEditAuthz().booleanValue()) {
340             return true;
341         }
342 
343         return isAuthorizedByTemplate(view, widget, model, KimConstants.PermissionTemplateNames.EDIT_WIDGET, user, null,
344                 null, false);
345     }
346 
347     /**
348      * @see ViewAuthorizer#canViewWidget(org.kuali.rice.krad.uif.view.View, org.kuali.rice.krad.uif.view.ViewModel,
349      * org.kuali.rice.krad.uif.widget.Widget, java.lang.String, org.kuali.rice.kim.api.identity.Person)
350      */
351     public boolean canViewWidget(View view, ViewModel model, Widget widget, String widgetId, Person user) {
352         ComponentSecurity componentSecurity = widget.getComponentSecurity();
353 
354         // check component security exists
355         if (componentSecurity == null) {
356             return true;
357         }
358 
359         // check view widget authz flag is set
360         if (componentSecurity.isViewAuthz() == null || !componentSecurity.isViewAuthz().booleanValue()) {
361             return true;
362         }
363 
364         return isAuthorizedByTemplate(view, widget, model, KimConstants.PermissionTemplateNames.VIEW_WIDGET, user, null,
365                 null, false);
366     }
367 
368     /**
369      * @see ViewAuthorizer#canPerformAction(org.kuali.rice.krad.uif.view.View, org.kuali.rice.krad.uif.view.ViewModel,
370      * org.kuali.rice.krad.uif.element.Action, java.lang.String, java.lang.String, org.kuali.rice.kim.api.identity.Person)
371      */
372     public boolean canPerformAction(View view, ViewModel model, Action action, String actionEvent,
373             String actionId, Person user) {
374         // check action authz flag is set
375         if ((action.getActionSecurity() == null) || !action.getActionSecurity().isPerformActionAuthz()) {
376             return true;
377         }
378 
379         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
380         if (StringUtils.isNotBlank(actionEvent)) {
381             additionalPermissionDetails.put(KimConstants.AttributeConstants.ACTION_EVENT, actionEvent);
382         }
383 
384         return isAuthorizedByTemplate(view, action, model, KimConstants.PermissionTemplateNames.PERFORM_ACTION,
385                 user, additionalPermissionDetails, null, false);
386     }
387 
388     public boolean canEditLine(View view, ViewModel model, CollectionGroup collectionGroup,
389             String collectionPropertyName, Object line, Person user) {
390         // check edit line authz flag is set
391         if ((collectionGroup.getCollectionGroupSecurity() == null) || !collectionGroup.getCollectionGroupSecurity()
392                 .isEditLineAuthz()) {
393             return true;
394         }
395 
396         return isAuthorizedByTemplate(view, collectionGroup, model, KimConstants.PermissionTemplateNames.EDIT_LINE,
397                 user, null, null, false);
398     }
399 
400     public boolean canViewLine(View view, ViewModel model, CollectionGroup collectionGroup,
401             String collectionPropertyName, Object line, Person user) {
402         // check view line authz flag is set
403         if ((collectionGroup.getCollectionGroupSecurity() == null) || !collectionGroup.getCollectionGroupSecurity()
404                 .isViewLineAuthz()) {
405             return true;
406         }
407 
408         return isAuthorizedByTemplate(view, collectionGroup, model, KimConstants.PermissionTemplateNames.VIEW_LINE,
409                 user, null, null, false);
410     }
411 
412     public boolean canEditLineField(View view, ViewModel model, CollectionGroup collectionGroup,
413             String collectionPropertyName, Object line, Field field, String propertyName, Person user) {
414         FieldSecurity fieldSecurity = field.getFieldSecurity();
415 
416         // check field security exists
417         if (fieldSecurity == null) {
418             return true;
419         }
420 
421         // first check hide flag is set (lower precedence)
422         if (fieldSecurity.isEditInLineAuthz() == null && !isDataFieldAttributeSecurityHide(field)) {
423             return true;
424         }
425 
426         // then check edit line field authz flag is set (higher precedence)
427         if (fieldSecurity.isEditInLineAuthz() != null && !fieldSecurity.isEditInLineAuthz().booleanValue()) {
428             return true;
429         }
430 
431         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
432         additionalPermissionDetails.put(KimConstants.AttributeConstants.GROUP_ID, collectionGroup.getId());
433         additionalPermissionDetails.put(KimConstants.AttributeConstants.COLLECTION_PROPERTY_NAME,
434                 collectionGroup.getPropertyName());
435 
436         return isAuthorizedByTemplate(view, field, model,
437                 KimConstants.PermissionTemplateNames.EDIT_LINE_FIELD, user, additionalPermissionDetails, null, false);
438     }
439 
440     public boolean canViewLineField(View view, ViewModel model, CollectionGroup collectionGroup,
441             String collectionPropertyName, Object line, Field field, String propertyName, Person user) {
442         FieldSecurity fieldSecurity = field.getFieldSecurity();
443 
444         // check field security exists
445         if (fieldSecurity == null) {
446             return true;
447         }
448 
449         // first check hide flag is set (lower precedence)
450         if (fieldSecurity.isViewInLineAuthz() == null && !isDataFieldAttributeSecurityHide(field)) {
451             return true;
452         }
453 
454         // then check view line field authz flag is set (higher precedence)
455         if (fieldSecurity.isViewInLineAuthz() != null && !fieldSecurity.isViewInLineAuthz().booleanValue()) {
456             return true;
457         }
458 
459         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
460         additionalPermissionDetails.put(KimConstants.AttributeConstants.GROUP_ID, collectionGroup.getId());
461         additionalPermissionDetails.put(KimConstants.AttributeConstants.COLLECTION_PROPERTY_NAME,
462                 collectionGroup.getPropertyName());
463 
464         return isAuthorizedByTemplate(view, field, model,
465                 KimConstants.PermissionTemplateNames.VIEW_LINE_FIELD, user, additionalPermissionDetails, null, false);
466     }
467 
468     public boolean canPerformLineAction(View view, ViewModel model, CollectionGroup collectionGroup,
469             String collectionPropertyName, Object line, Action action, String actionEvent, String actionId,
470             Person user) {
471         // check perform line action authz flag is set
472         if ((action.getActionSecurity() == null) || !action.getActionSecurity().isPerformLineActionAuthz()) {
473             return true;
474         }
475 
476         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
477         additionalPermissionDetails.put(KimConstants.AttributeConstants.GROUP_ID, collectionGroup.getId());
478         additionalPermissionDetails.put(KimConstants.AttributeConstants.COLLECTION_PROPERTY_NAME,
479                 collectionGroup.getPropertyName());
480         if (StringUtils.isNotBlank(actionEvent)) {
481             additionalPermissionDetails.put(KimConstants.AttributeConstants.ACTION_EVENT, actionEvent);
482         }
483 
484         return isAuthorizedByTemplate(view, action, model,
485                 KimConstants.PermissionTemplateNames.PERFORM_LINE_ACTION, user, additionalPermissionDetails, null,
486                 false);
487     }
488 
489     /**
490      * Retrieves the object from the model that is used as the context for permission checks
491      *
492      * <p>
493      * Used to derive namespace and component details. Subclasses can override to return the object to be used
494      * </p>
495      *
496      * @param view view instance the permission checks are being done for
497      * @param model model object containing the data and from which the data object should be pulled
498      * @return data object instance to use
499      */
500     protected Object getDataObjectContext(View view, ViewModel model) {
501         Object dataObject = model;
502 
503         if (StringUtils.isNotBlank(view.getDefaultBindingObjectPath())) {
504             Object defaultObject = ObjectPropertyUtils.getPropertyValue(model, view.getDefaultBindingObjectPath());
505             if (defaultObject != null) {
506                 dataObject = defaultObject;
507             }
508         }
509 
510         return dataObject;
511     }
512 
513     /**
514      * Builds the permission details map for a field which includes the component namespace, component name, and
515      * field id, in addition to property name for data binding fields
516      *
517      * @param view view instance the field belongs to
518      * @param dataObject default object from the data model (used for subclasses to build details)
519      * @param field field instance the details are being built for
520      * @return permission details for the field
521      */
522     protected Map<String, String> getFieldPermissionDetails(View view, Object dataObject, Field field) {
523         Map<String, String> permissionDetails = new HashMap<String, String>();
524 
525         permissionDetails.put(KimConstants.AttributeConstants.NAMESPACE_CODE, view.getNamespaceCode());
526         permissionDetails.put(KimConstants.AttributeConstants.VIEW_ID, view.getId());
527         permissionDetails.put(KimConstants.AttributeConstants.FIELD_ID, field.getId());
528 
529         if (field instanceof DataBinding) {
530             permissionDetails.put(KimConstants.AttributeConstants.PROPERTY_NAME,
531                     ((DataBinding) field).getPropertyName());
532         }
533 
534         return permissionDetails;
535     }
536 
537     /**
538      * Builds the permission details map for a group which includes the component namespace, component name, and
539      * group id, in addition to property name for collection groups
540      *
541      * @param view view instance the group belongs to
542      * @param dataObject default object from the data model (used for subclasses to build details)
543      * @param group group instance the details are being built for
544      * @return permission details for the group
545      */
546     protected Map<String, String> getGroupPermissionDetails(View view, Object dataObject, Group group) {
547         Map<String, String> permissionDetails = new HashMap<String, String>();
548 
549         permissionDetails.put(KimConstants.AttributeConstants.NAMESPACE_CODE, view.getNamespaceCode());
550         permissionDetails.put(KimConstants.AttributeConstants.VIEW_ID, view.getId());
551         permissionDetails.put(KimConstants.AttributeConstants.GROUP_ID, group.getId());
552 
553         if (group instanceof CollectionGroup) {
554             permissionDetails.put(KimConstants.AttributeConstants.COLLECTION_PROPERTY_NAME,
555                     ((CollectionGroup) group).getPropertyName());
556         }
557 
558         return permissionDetails;
559     }
560 
561     /**
562      * Builds the permission details map for a widget which includes the namespace, view id, and
563      * widget id
564      *
565      * @param view view instance the widget belongs to
566      * @param dataObject default object from the data model (used for subclasses to build details)
567      * @param widget group instance the details are being built for
568      * @return permission details for group
569      */
570     protected Map<String, String> getWidgetPermissionDetails(View view, Object dataObject, Widget widget) {
571         Map<String, String> permissionDetails = new HashMap<String, String>();
572 
573         permissionDetails.put(KimConstants.AttributeConstants.NAMESPACE_CODE, view.getNamespaceCode());
574         permissionDetails.put(KimConstants.AttributeConstants.VIEW_ID, view.getId());
575         permissionDetails.put(KimConstants.AttributeConstants.WIDGET_ID, widget.getId());
576 
577         return permissionDetails;
578     }
579     
580     /**
581      * Builds the permission details map for an action which includes the namespace, view id, and
582      * action id and event
583      *
584      * @param view view instance the widget belongs to
585      * @param dataObject default object from the data model (used for subclasses to build details)
586      * @param action action instance the details are being built for
587      * @return permission details for action
588      */
589     protected Map<String, String> getActionPermissionDetails(View view, Object dataObject, Action action) {
590         Map<String, String> permissionDetails = new HashMap<String, String>();
591 
592         permissionDetails.put(KimConstants.AttributeConstants.NAMESPACE_CODE, view.getNamespaceCode());
593         permissionDetails.put(KimConstants.AttributeConstants.VIEW_ID, view.getId());
594         permissionDetails.put(KimConstants.AttributeConstants.FIELD_ID, action.getId());
595 
596         return permissionDetails;
597     }
598 
599     /**
600      * Performs a permission check for the given template name in the context of the given view and component
601      *
602      * <p>
603      * First standard permission details are added based on the type of component the permission check is being
604      * done for.
605      * Then the {@link ComponentSecurity} of the given component is used to pick up additional permission details and
606      * role qualifiers.
607      * </p>
608      *
609      * @param view view instance the component belongs to
610      * @param component component instance the permission check is being done for
611      * @param model object containing the views data
612      * @param permissionTemplateName template name for the permission to check
613      * @param user user to perform the authorization for
614      * @param additionalPermissionDetails additional key/value pairs to pass with the permission details
615      * @param additionalRoleQualifications additional key/value paris to pass with the role qualifiers
616      * @param checkPermissionExistence boolean indicating whether the existence of the permission should be checked
617      * before performing the authorization
618      * @return whether or not the user has authorization; this will be the case if the user has been
619      * granted the permission or checkPermissionExistence is true and the permission does not exist
620      */
621     protected boolean isAuthorizedByTemplate(View view, Component component, ViewModel model,
622             String permissionTemplateName, Person user, Map<String, String> additionalPermissionDetails,
623             Map<String, String> additionalRoleQualifications, boolean checkPermissionExistence) {
624         Map<String, String> permissionDetails = new HashMap<String, String>();
625         Map<String, String> roleQualifications = new HashMap<String, String>();
626 
627         if (additionalPermissionDetails != null) {
628             permissionDetails.putAll(additionalPermissionDetails);
629         }
630 
631         if (additionalRoleQualifications != null) {
632             roleQualifications.putAll(additionalRoleQualifications);
633         }
634 
635         Object dataObjectForContext = getDataObjectContext(view, model);
636 
637         // add permission details depending on the type of component
638         if (component instanceof Field) {
639             permissionDetails.putAll(getFieldPermissionDetails(view, dataObjectForContext, (Field) component));
640         } else if (component instanceof Group) {
641             permissionDetails.putAll(getGroupPermissionDetails(view, dataObjectForContext, (Group) component));
642         } else if (component instanceof Widget) {
643             permissionDetails.putAll(getWidgetPermissionDetails(view, dataObjectForContext, (Widget) component));
644         } else if (component instanceof Action) {
645             permissionDetails.putAll(getActionPermissionDetails(view, dataObjectForContext, (Action) component));
646         }
647 
648         // pick up additional attributes and overrides from component security
649         ComponentSecurity componentSecurity = component.getComponentSecurity();
650 
651         // add configured overrides
652         if (componentSecurity != null) {
653             if (StringUtils.isNotBlank(componentSecurity.getNamespaceAttribute())) {
654                 permissionDetails.put(KimConstants.AttributeConstants.NAMESPACE_CODE,
655                         componentSecurity.getNamespaceAttribute());
656             }
657 
658             if (StringUtils.isNotBlank(componentSecurity.getComponentAttribute())) {
659                 permissionDetails.put(KimConstants.AttributeConstants.COMPONENT_NAME,
660                         componentSecurity.getComponentAttribute());
661             }
662 
663             if (StringUtils.isNotBlank(componentSecurity.getIdAttribute())) {
664                 if (component instanceof Field) {
665                     permissionDetails.put(KimConstants.AttributeConstants.FIELD_ID, componentSecurity.getIdAttribute());
666                 } else if (component instanceof Group) {
667                     permissionDetails.put(KimConstants.AttributeConstants.GROUP_ID, componentSecurity.getIdAttribute());
668                 } else if (component instanceof Widget) {
669                     permissionDetails.put(KimConstants.AttributeConstants.WIDGET_ID,
670                             componentSecurity.getIdAttribute());
671                 }
672             }
673 
674             if (componentSecurity.getAdditionalPermissionDetails() != null) {
675                 permissionDetails.putAll(componentSecurity.getAdditionalPermissionDetails());
676             }
677 
678             if (componentSecurity.getAdditionalRoleQualifiers() != null) {
679                 roleQualifications.putAll(componentSecurity.getAdditionalRoleQualifiers());
680             }
681         }
682 
683         boolean result = true;
684         if (!checkPermissionExistence || (checkPermissionExistence && permissionExistsByTemplate(dataObjectForContext,
685                 KRADConstants.KRAD_NAMESPACE, permissionTemplateName, permissionDetails))) {
686             result = isAuthorizedByTemplate(dataObjectForContext, KRADConstants.KRAD_NAMESPACE, permissionTemplateName,
687                     user.getPrincipalId(), permissionDetails, roleQualifications);
688 
689             if (LOG.isDebugEnabled()) {
690                 LOG.debug("Performed permission check for: " + permissionTemplateName + " and got result: " + result);
691             }
692         }
693 
694         return result;
695     }
696 
697     /**
698      * Indicates whether the environment is non production and unmasking is not enabled by system parameter
699      *
700      * @return true if unmasking is turned off, false if unmasking is allowed
701      */
702     private boolean isNonProductionEnvAndUnmaskingTurnedOff() {
703         return !getConfigurationService().getPropertyValueAsString(KRADConstants.PROD_ENVIRONMENT_CODE_KEY).
704                 equalsIgnoreCase(getConfigurationService().getPropertyValueAsString(KRADConstants.ENVIRONMENT_KEY))
705                 && !getConfigurationService().getPropertyValueAsBoolean(KRADConstants.ENABLE_NONPRODUCTION_UNMASKING);
706     }
707 
708     /**
709      * Determines whether {@code AttributeSecurity} is set on the {@code DataField} and if it is, whether its hide
710      * attribute is enabled.
711      *
712      * @param field the field to check for the hide attribute
713      *
714      * @return true if the hide attribute is enabled, false otherwise
715      */
716     private boolean isDataFieldAttributeSecurityHide(Field field) {
717         if (field instanceof DataField) {
718             DataField dataField = (DataField) field;
719             DataFieldSecurity dataFieldSecurity = dataField.getDataFieldSecurity();
720 
721             if (dataFieldSecurity == null) {
722                 return false;
723             }
724 
725             if (dataFieldSecurity.getAttributeSecurity() == null || !dataFieldSecurity.getAttributeSecurity().isHide()) {
726                 return false;
727             }
728 
729             return true;
730         } else {
731             return false;
732         }
733     }
734 
735     @BeanTagAttribute(name="configurationService",type= BeanTagAttribute.AttributeType.SINGLEBEAN)
736     protected ConfigurationService getConfigurationService() {
737         if (configurationService == null) {
738             return CoreApiServiceLocator.getKualiConfigurationService();
739         }
740         return configurationService;
741     }
742 
743     public void setConfigurationService(ConfigurationService configurationService) {
744         this.configurationService = configurationService;
745     }
746 
747 }