View Javadoc

1   /**
2    * Copyright 2005-2013 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         return isAuthorizedByTemplate(document, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE,
183                 KimConstants.PermissionTemplateNames.CANCEL_DOCUMENT, user.getPrincipalId());
184     }
185 
186     public boolean canRecall(Document document, Person user) {
187         return KewApiServiceLocator.getWorkflowDocumentActionsService().determineValidActions(document.getDocumentNumber(), user.getPrincipalId()).getValidActions().contains(ActionType.RECALL);
188     }
189 
190     public boolean canCopy(Document document, Person user) {
191         return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
192                 KimConstants.PermissionTemplateNames.COPY_DOCUMENT, user.getPrincipalId());
193     }
194 
195     public boolean canPerformRouteReport(Document document, Person user) {
196         return true;
197     }
198 
199     public boolean canBlanketApprove(Document document, Person user) {
200         return isAuthorizedByTemplate(document, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE,
201                 KimConstants.PermissionTemplateNames.BLANKET_APPROVE_DOCUMENT, user.getPrincipalId());
202     }
203 
204     public boolean canApprove(Document document, Person user) {
205         return canTakeRequestedAction(document, KewApiConstants.ACTION_REQUEST_APPROVE_REQ, user);
206     }
207 
208     public boolean canDisapprove(Document document, Person user) {
209         return canApprove(document, user);
210     }
211 
212     public boolean canSendNoteFyi(Document document, Person user) {
213         return canSendAdHocRequests(document, KewApiConstants.ACTION_REQUEST_FYI_REQ, user);
214     }
215 
216     public boolean canFyi(Document document, Person user) {
217         return canTakeRequestedAction(document, KewApiConstants.ACTION_REQUEST_FYI_REQ, user);
218     }
219 
220     public boolean canAcknowledge(Document document, Person user) {
221         return canTakeRequestedAction(document, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, user);
222     }
223 
224     public boolean canReceiveAdHoc(Document document, Person user, String actionRequestCode) {
225         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
226         additionalPermissionDetails.put(KimConstants.AttributeConstants.ACTION_REQUEST_CD, actionRequestCode);
227         return isAuthorizedByTemplate(document, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE,
228                 KimConstants.PermissionTemplateNames.AD_HOC_REVIEW_DOCUMENT, user.getPrincipalId(),
229                 additionalPermissionDetails, Collections.<String, String>emptyMap());
230     }
231 
232     public boolean canOpen(Document document, Person user) {
233         return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
234                 KimConstants.PermissionTemplateNames.OPEN_DOCUMENT, user.getPrincipalId());
235     }
236 
237     public boolean canAddNoteAttachment(Document document, String attachmentTypeCode, Person user) {
238         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
239         if (attachmentTypeCode != null) {
240             additionalPermissionDetails.put(KimConstants.AttributeConstants.ATTACHMENT_TYPE_CODE, attachmentTypeCode);
241         }
242         return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
243                 KimConstants.PermissionTemplateNames.ADD_NOTE_ATTACHMENT, user.getPrincipalId(),
244                 additionalPermissionDetails, Collections.<String, String>emptyMap());
245     }
246 
247     public boolean canDeleteNoteAttachment(Document document, String attachmentTypeCode, String createdBySelfOnly,
248             Person user) {
249         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
250         if (attachmentTypeCode != null) {
251             additionalPermissionDetails.put(KimConstants.AttributeConstants.ATTACHMENT_TYPE_CODE, attachmentTypeCode);
252         }
253         additionalPermissionDetails.put(KimConstants.AttributeConstants.CREATED_BY_SELF, createdBySelfOnly);
254         return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
255                 KimConstants.PermissionTemplateNames.DELETE_NOTE_ATTACHMENT, user.getPrincipalId(),
256                 additionalPermissionDetails, Collections.<String, String>emptyMap());
257     }
258 
259     public boolean canViewNoteAttachment(Document document, String attachmentTypeCode, Person user) {
260         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
261         if (attachmentTypeCode != null) {
262             additionalPermissionDetails.put(KimConstants.AttributeConstants.ATTACHMENT_TYPE_CODE, attachmentTypeCode);
263         }
264         return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
265                 KimConstants.PermissionTemplateNames.VIEW_NOTE_ATTACHMENT, user.getPrincipalId(),
266                 additionalPermissionDetails, Collections.<String, String>emptyMap());
267     }
268 
269     public boolean canViewNoteAttachment(Document document, String attachmentTypeCode, String authorUniversalIdentifier,
270             Person user) {
271         return canViewNoteAttachment(document, attachmentTypeCode, user);
272     }
273 
274     public boolean canSendAdHocRequests(Document document, String actionRequestCd, Person user) {
275         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
276         if (actionRequestCd != null) {
277             additionalPermissionDetails.put(KimConstants.AttributeConstants.ACTION_REQUEST_CD, actionRequestCd);
278         }
279         return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
280                 KimConstants.PermissionTemplateNames.SEND_AD_HOC_REQUEST, user.getPrincipalId(),
281                 additionalPermissionDetails, Collections.<String, String>emptyMap());
282     }
283 
284     public boolean canEditDocumentOverview(Document document, Person user) {
285         return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
286                 KimConstants.PermissionTemplateNames.EDIT_DOCUMENT, user.getPrincipalId()) && this.isDocumentInitiator(
287                 document, user);
288     }
289 
290     public boolean canSendAnyTypeAdHocRequests(Document document, Person user) {
291         if (canSendAdHocRequests(document, KewApiConstants.ACTION_REQUEST_FYI_REQ, user)) {
292             RoutePath routePath = KewApiServiceLocator.getDocumentTypeService().getRoutePathForDocumentTypeName(
293                     document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName());
294             ProcessDefinition processDefinition = routePath.getPrimaryProcess();
295             if (processDefinition != null) {
296                 if (processDefinition.getInitialRouteNode() == null) {
297                     return false;
298                 }
299             } else {
300                 return false;
301             }
302             return true;
303         } else if (canSendAdHocRequests(document, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, user)) {
304             return true;
305         }
306         return canSendAdHocRequests(document, KewApiConstants.ACTION_REQUEST_APPROVE_REQ, user);
307     }
308 
309     public boolean canTakeRequestedAction(Document document, String actionRequestCode, Person user) {
310         Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
311         additionalPermissionDetails.put(KimConstants.AttributeConstants.ACTION_REQUEST_CD, actionRequestCode);
312         return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
313                 KimConstants.PermissionTemplateNames.TAKE_REQUESTED_ACTION, user.getPrincipalId(),
314                 additionalPermissionDetails, Collections.<String, String>emptyMap());
315     }
316 
317     @Override
318     protected void addPermissionDetails(Object dataObject, Map<String, String> attributes) {
319         super.addPermissionDetails(dataObject, attributes);
320         if (dataObject instanceof Document) {
321             addStandardAttributes((Document) dataObject, attributes);
322         }
323     }
324 
325     @Override
326     protected void addRoleQualification(Object dataObject, Map<String, String> attributes) {
327         super.addRoleQualification(dataObject, attributes);
328         if (dataObject instanceof Document) {
329             addStandardAttributes((Document) dataObject, attributes);
330         }
331     }
332 
333     protected void addStandardAttributes(Document document, Map<String, String> attributes) {
334         WorkflowDocument wd = document.getDocumentHeader().getWorkflowDocument();
335         attributes.put(KimConstants.AttributeConstants.DOCUMENT_NUMBER, document.getDocumentNumber());
336         attributes.put(KimConstants.AttributeConstants.DOCUMENT_TYPE_NAME, wd.getDocumentTypeName());
337         if (wd.isInitiated() || wd.isSaved()) {
338             attributes.put(KimConstants.AttributeConstants.ROUTE_NODE_NAME, PRE_ROUTING_ROUTE_NAME);
339         } else {
340             attributes.put(KimConstants.AttributeConstants.ROUTE_NODE_NAME,
341                     KRADServiceLocatorWeb.getWorkflowDocumentService().getCurrentRouteNodeNames(wd));
342         }
343         attributes.put(KimConstants.AttributeConstants.ROUTE_STATUS_CODE, wd.getStatus().getCode());
344     }
345 
346     protected boolean isDocumentInitiator(Document document, Person user) {
347         WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
348         return workflowDocument.getInitiatorPrincipalId().equalsIgnoreCase(user.getPrincipalId());
349     }
350 }