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