View Javadoc
1   /**
2    * Copyright 2005-2016 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.document.authorization;
17  
18  import org.apache.commons.logging.Log;
19  import org.apache.commons.logging.LogFactory;
20  import org.kuali.rice.kew.api.KewApiConstants;
21  import org.kuali.rice.kew.api.KewApiServiceLocator;
22  import org.kuali.rice.kew.api.WorkflowDocument;
23  import org.kuali.rice.kew.api.action.ActionType;
24  import org.kuali.rice.kew.api.doctype.ProcessDefinition;
25  import org.kuali.rice.kew.api.doctype.RoutePath;
26  import org.kuali.rice.kim.api.KimConstants;
27  import org.kuali.rice.kim.api.identity.Person;
28  import org.kuali.rice.kns.bo.authorization.BusinessObjectAuthorizerBase;
29  import org.kuali.rice.krad.document.Document;
30  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
31  import org.kuali.rice.krad.util.KRADConstants;
32  
33  import java.util.Collections;
34  import java.util.HashMap;
35  import java.util.Map;
36  import java.util.Set;
37  
38  /**
39   * DocumentAuthorizer containing common, reusable document-level authorization
40   * code.
41   */
42  public class DocumentAuthorizerBase extends BusinessObjectAuthorizerBase implements DocumentAuthorizer {
43      protected static Log LOG = LogFactory.getLog(DocumentAuthorizerBase.class);
44  
45      public static final String PRE_ROUTING_ROUTE_NAME = "PreRoute";
46      public static final String EDIT_MODE_DEFAULT_TRUE_VALUE = "TRUE";
47      public static final String USER_SESSION_METHOD_TO_CALL_OBJECT_KEY = "METHOD_TO_CALL_KEYS_METHOD_OBJECT_KEY";
48      public static final String USER_SESSION_METHOD_TO_CALL_COMPLETE_OBJECT_KEY =
49              "METHOD_TO_CALL_KEYS_COMPLETE_OBJECT_KEY";
50      public static final String USER_SESSION_METHOD_TO_CALL_COMPLETE_MARKER = "_EXITING";
51  
52      /**
53       * Individual document families will need to reimplement this according to
54       * their own needs; this version should be good enough to be usable during
55       * initial development.
56       */
57      public Set<String> getDocumentActions(Document document, Person user, Set<String> documentActions) {
58          if (LOG.isDebugEnabled()) {
59              LOG.debug("calling DocumentAuthorizerBase.getDocumentActionFlags for document '"
60                      + document.getDocumentNumber()
61                      + "'. user '"
62                      + user.getPrincipalName()
63                      + "'");
64          }
65          if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_EDIT) && !canEdit(document, user)) {
66              documentActions.remove(KRADConstants.KUALI_ACTION_CAN_EDIT);
67          }
68  
69          if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_COPY) && !canCopy(document, user)) {
70              documentActions.remove(KRADConstants.KUALI_ACTION_CAN_COPY);
71          }
72  
73          if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_CLOSE) && !canClose(document, user)) {
74              documentActions.remove(KRADConstants.KUALI_ACTION_CAN_CLOSE);
75          }
76  
77          if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_RELOAD) && !canReload(document, user)) {
78              documentActions.remove(KRADConstants.KUALI_ACTION_CAN_RELOAD);
79          }
80  
81          if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_BLANKET_APPROVE) && !canBlanketApprove(document, user)) {
82              documentActions.remove(KRADConstants.KUALI_ACTION_CAN_BLANKET_APPROVE);
83          }
84  
85          if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_CANCEL) && !canCancel(document, user)) {
86              documentActions.remove(KRADConstants.KUALI_ACTION_CAN_CANCEL);
87          }
88  
89          if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_RECALL) && !canRecall(document, user)) {
90              documentActions.remove(KRADConstants.KUALI_ACTION_CAN_RECALL);
91          }
92  
93          if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_SAVE) && !canSave(document, user)) {
94              documentActions.remove(KRADConstants.KUALI_ACTION_CAN_SAVE);
95          }
96  
97          if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_ROUTE) && !canRoute(document, user)) {
98              documentActions.remove(KRADConstants.KUALI_ACTION_CAN_ROUTE);
99          }
100 
101         if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_ACKNOWLEDGE) && !canAcknowledge(document, user)) {
102             documentActions.remove(KRADConstants.KUALI_ACTION_CAN_ACKNOWLEDGE);
103         }
104 
105         if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_FYI) && !canFyi(document, user)) {
106             documentActions.remove(KRADConstants.KUALI_ACTION_CAN_FYI);
107         }
108 
109         if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_APPROVE) && !canApprove(document, user)) {
110             documentActions.remove(KRADConstants.KUALI_ACTION_CAN_APPROVE);
111         }
112 
113         if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_DISAPPROVE) && !canDisapprove(document, user)) {
114             documentActions.remove(KRADConstants.KUALI_ACTION_CAN_DISAPPROVE);
115         }
116 
117         if (!canSendAnyTypeAdHocRequests(document, user)) {
118             documentActions.remove(KRADConstants.KUALI_ACTION_CAN_ADD_ADHOC_REQUESTS);
119             documentActions.remove(KRADConstants.KUALI_ACTION_CAN_SEND_ADHOC_REQUESTS);
120             documentActions.remove(KRADConstants.KUALI_ACTION_CAN_SEND_NOTE_FYI);
121         }
122 
123         if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_SEND_NOTE_FYI) && !canSendNoteFyi(document, user)) {
124             documentActions.remove(KRADConstants.KUALI_ACTION_CAN_SEND_NOTE_FYI);
125         }
126 
127         if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_ANNOTATE) && !canAnnotate(document, user)) {
128             documentActions.remove(KRADConstants.KUALI_ACTION_CAN_ANNOTATE);
129         }
130 
131         if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_EDIT_DOCUMENT_OVERVIEW) && !canEditDocumentOverview(
132                 document, user)) {
133             documentActions.remove(KRADConstants.KUALI_ACTION_CAN_EDIT_DOCUMENT_OVERVIEW);
134         }
135 
136         if (documentActions.contains(KRADConstants.KUALI_ACTION_PERFORM_ROUTE_REPORT) && !canPerformRouteReport(document,
137                 user)) {
138             documentActions.remove(KRADConstants.KUALI_ACTION_PERFORM_ROUTE_REPORT);
139         }
140 
141         return documentActions;
142     }
143 
144     public boolean canInitiate(String documentTypeName, Person user) {
145         String nameSpaceCode = KRADConstants.KUALI_RICE_SYSTEM_NAMESPACE;
146         Map<String, String> permissionDetails = new HashMap<String, String>();
147         permissionDetails.put(KimConstants.AttributeConstants.DOCUMENT_TYPE_NAME, documentTypeName);
148         return getPermissionService().isAuthorizedByTemplate(user.getPrincipalId(), nameSpaceCode,
149                 KimConstants.PermissionTemplateNames.INITIATE_DOCUMENT, permissionDetails,
150                 Collections.<String, String>emptyMap());
151     }
152 
153     public boolean canEdit(Document document, Person user) {
154         // KULRICE-7864: document can be editable on adhoc route for completion 
155         return document.getDocumentHeader().getWorkflowDocument().isCompletionRequested()
156                 || isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE, KimConstants.PermissionTemplateNames.EDIT_DOCUMENT, user.getPrincipalId());
157     }
158 
159     public boolean canAnnotate(Document document, Person user) {
160         return canEdit(document, user);
161     }
162 
163     public boolean canReload(Document document, Person user) {
164         return true;
165     }
166 
167     public boolean canClose(Document document, Person user) {
168         return true;
169     }
170 
171     public boolean canSave(Document document, Person user) {
172         return isAuthorizedByTemplate(document, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE,
173                 KimConstants.PermissionTemplateNames.SAVE_DOCUMENT, user.getPrincipalId());
174     }
175 
176     public boolean canRoute(Document document, Person user) {
177         return isAuthorizedByTemplate(document, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE,
178                 KimConstants.PermissionTemplateNames.ROUTE_DOCUMENT, user.getPrincipalId());
179     }
180 
181     public boolean canCancel(Document document, Person user) {
182         // KULRICE-8762: CANCEL button should be enabled for a person who is doing COMPLETE action 
183         boolean isCompletionRequested = document.getDocumentHeader().getWorkflowDocument().isCompletionRequested();
184         return isCompletionRequested || isAuthorizedByTemplate(document, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE,
185                 KimConstants.PermissionTemplateNames.CANCEL_DOCUMENT, user.getPrincipalId());
186     }
187 
188     public boolean canRecall(Document document, Person user) {
189         return KewApiServiceLocator.getWorkflowDocumentActionsService().determineValidActions(document.getDocumentNumber(), user.getPrincipalId()).getValidActions().contains(ActionType.RECALL);
190     }
191 
192     public boolean canCopy(Document document, Person user) {
193         return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
194                 KimConstants.PermissionTemplateNames.COPY_DOCUMENT, user.getPrincipalId());
195     }
196 
197     public boolean canPerformRouteReport(Document document, Person user) {
198         return true;
199     }
200 
201     public boolean canBlanketApprove(Document document, Person user) {
202         return isAuthorizedByTemplate(document, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE,
203                 KimConstants.PermissionTemplateNames.BLANKET_APPROVE_DOCUMENT, user.getPrincipalId());
204     }
205 
206     public boolean canApprove(Document document, Person user) {
207         return canTakeRequestedAction(document, KewApiConstants.ACTION_REQUEST_APPROVE_REQ, user);
208     }
209 
210     public boolean canDisapprove(Document document, Person user) {
211         return canApprove(document, user);
212     }
213 
214     public boolean canSendNoteFyi(Document document, Person user) {
215         return canSendAdHocRequests(document, KewApiConstants.ACTION_REQUEST_FYI_REQ, user);
216     }
217 
218     public boolean canFyi(Document document, Person user) {
219         return canTakeRequestedAction(document, KewApiConstants.ACTION_REQUEST_FYI_REQ, user);
220     }
221 
222     public boolean canAcknowledge(Document document, Person user) {
223         return canTakeRequestedAction(document, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, user);
224     }
225 
226     public boolean canReceiveAdHoc(Document document, Person user, String actionRequestCode) {
227         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
228         additionalPermissionDetails.put(KimConstants.AttributeConstants.ACTION_REQUEST_CD, actionRequestCode);
229         return isAuthorizedByTemplate(document, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE,
230                 KimConstants.PermissionTemplateNames.AD_HOC_REVIEW_DOCUMENT, user.getPrincipalId(),
231                 additionalPermissionDetails, Collections.<String, String>emptyMap());
232     }
233 
234     public boolean canOpen(Document document, Person user) {
235         return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
236                 KimConstants.PermissionTemplateNames.OPEN_DOCUMENT, user.getPrincipalId());
237     }
238 
239     public boolean canAddNoteAttachment(Document document, String attachmentTypeCode, Person user) {
240         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
241         if (attachmentTypeCode != null) {
242             additionalPermissionDetails.put(KimConstants.AttributeConstants.ATTACHMENT_TYPE_CODE, attachmentTypeCode);
243         }
244         return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
245                 KimConstants.PermissionTemplateNames.ADD_NOTE_ATTACHMENT, user.getPrincipalId(),
246                 additionalPermissionDetails, Collections.<String, String>emptyMap());
247     }
248 
249     public boolean canDeleteNoteAttachment(Document document, String attachmentTypeCode, String createdBySelfOnly,
250             Person user) {
251         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
252         if (attachmentTypeCode != null) {
253             additionalPermissionDetails.put(KimConstants.AttributeConstants.ATTACHMENT_TYPE_CODE, attachmentTypeCode);
254         }
255         additionalPermissionDetails.put(KimConstants.AttributeConstants.CREATED_BY_SELF, createdBySelfOnly);
256         return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
257                 KimConstants.PermissionTemplateNames.DELETE_NOTE_ATTACHMENT, user.getPrincipalId(),
258                 additionalPermissionDetails, Collections.<String, String>emptyMap());
259     }
260 
261     public boolean canViewNoteAttachment(Document document, String attachmentTypeCode, Person user) {
262         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
263         if (attachmentTypeCode != null) {
264             additionalPermissionDetails.put(KimConstants.AttributeConstants.ATTACHMENT_TYPE_CODE, attachmentTypeCode);
265         }
266         return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
267                 KimConstants.PermissionTemplateNames.VIEW_NOTE_ATTACHMENT, user.getPrincipalId(),
268                 additionalPermissionDetails, Collections.<String, String>emptyMap());
269     }
270 
271     public boolean canViewNoteAttachment(Document document, String attachmentTypeCode, String authorUniversalIdentifier,
272             Person user) {
273         return canViewNoteAttachment(document, attachmentTypeCode, user);
274     }
275 
276     public boolean canSendAdHocRequests(Document document, String actionRequestCd, Person user) {
277         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
278         if (actionRequestCd != null) {
279             additionalPermissionDetails.put(KimConstants.AttributeConstants.ACTION_REQUEST_CD, actionRequestCd);
280         }
281         return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
282                 KimConstants.PermissionTemplateNames.SEND_AD_HOC_REQUEST, user.getPrincipalId(),
283                 additionalPermissionDetails, Collections.<String, String>emptyMap());
284     }
285 
286     public boolean canEditDocumentOverview(Document document, Person user) {
287         return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
288                 KimConstants.PermissionTemplateNames.EDIT_DOCUMENT, user.getPrincipalId()) && this.isDocumentInitiator(
289                 document, user);
290     }
291 
292     public boolean canSendAnyTypeAdHocRequests(Document document, Person user) {
293         if (canSendAdHocRequests(document, KewApiConstants.ACTION_REQUEST_FYI_REQ, user)) {
294             RoutePath routePath = KewApiServiceLocator.getDocumentTypeService().getRoutePathForDocumentTypeName(
295                     document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName());
296             ProcessDefinition processDefinition = routePath.getPrimaryProcess();
297             if (processDefinition != null) {
298                 if (processDefinition.getInitialRouteNode() == null) {
299                     return false;
300                 }
301             } else {
302                 return false;
303             }
304             return true;
305         } else if (canSendAdHocRequests(document, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, user)) {
306             return true;
307         }
308         return canSendAdHocRequests(document, KewApiConstants.ACTION_REQUEST_APPROVE_REQ, user);
309     }
310 
311     public boolean canTakeRequestedAction(Document document, String actionRequestCode, Person user) {
312         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
313         additionalPermissionDetails.put(KimConstants.AttributeConstants.ACTION_REQUEST_CD, actionRequestCode);
314         return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
315                 KimConstants.PermissionTemplateNames.TAKE_REQUESTED_ACTION, user.getPrincipalId(),
316                 additionalPermissionDetails, Collections.<String, String>emptyMap());
317     }
318 
319     @Override
320     protected void addPermissionDetails(Object dataObject, Map<String, String> attributes) {
321         super.addPermissionDetails(dataObject, attributes);
322         if (dataObject instanceof Document) {
323             addStandardAttributes((Document) dataObject, attributes);
324         }
325     }
326 
327     @Override
328     protected void addRoleQualification(Object dataObject, Map<String, String> attributes) {
329         super.addRoleQualification(dataObject, attributes);
330         if (dataObject instanceof Document) {
331             addStandardAttributes((Document) dataObject, attributes);
332         }
333     }
334 
335     protected void addStandardAttributes(Document document, Map<String, String> attributes) {
336         WorkflowDocument wd = document.getDocumentHeader().getWorkflowDocument();
337         attributes.put(KimConstants.AttributeConstants.DOCUMENT_NUMBER, document.getDocumentNumber());
338         attributes.put(KimConstants.AttributeConstants.DOCUMENT_TYPE_NAME, wd.getDocumentTypeName());
339         if (wd.isInitiated() || wd.isSaved()) {
340             attributes.put(KimConstants.AttributeConstants.ROUTE_NODE_NAME, PRE_ROUTING_ROUTE_NAME);
341         } else {
342             attributes.put(KimConstants.AttributeConstants.ROUTE_NODE_NAME,
343                     KRADServiceLocatorWeb.getWorkflowDocumentService().getCurrentRouteNodeNames(wd));
344         }
345         attributes.put(KimConstants.AttributeConstants.ROUTE_STATUS_CODE, wd.getStatus().getCode());
346     }
347 
348     protected boolean isDocumentInitiator(Document document, Person user) {
349         WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
350         return workflowDocument.getInitiatorPrincipalId().equalsIgnoreCase(user.getPrincipalId());
351     }
352 }