001 /**
002 * Copyright 2005-2013 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.rice.kns.document.authorization;
017
018 import org.apache.commons.logging.Log;
019 import org.apache.commons.logging.LogFactory;
020 import org.kuali.rice.kew.api.KewApiConstants;
021 import org.kuali.rice.kew.api.KewApiServiceLocator;
022 import org.kuali.rice.kew.api.WorkflowDocument;
023 import org.kuali.rice.kew.api.action.ActionType;
024 import org.kuali.rice.kew.api.doctype.ProcessDefinition;
025 import org.kuali.rice.kew.api.doctype.RoutePath;
026 import org.kuali.rice.kim.api.KimConstants;
027 import org.kuali.rice.kim.api.identity.Person;
028 import org.kuali.rice.kns.bo.authorization.BusinessObjectAuthorizerBase;
029 import org.kuali.rice.krad.document.Document;
030 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
031 import org.kuali.rice.krad.util.KRADConstants;
032
033 import java.util.Collections;
034 import java.util.HashMap;
035 import java.util.Map;
036 import java.util.Set;
037
038 /**
039 * DocumentAuthorizer containing common, reusable document-level authorization
040 * code.
041 */
042 public class DocumentAuthorizerBase extends BusinessObjectAuthorizerBase implements DocumentAuthorizer {
043 protected static Log LOG = LogFactory.getLog(DocumentAuthorizerBase.class);
044
045 public static final String PRE_ROUTING_ROUTE_NAME = "PreRoute";
046 public static final String EDIT_MODE_DEFAULT_TRUE_VALUE = "TRUE";
047 public static final String USER_SESSION_METHOD_TO_CALL_OBJECT_KEY = "METHOD_TO_CALL_KEYS_METHOD_OBJECT_KEY";
048 public static final String USER_SESSION_METHOD_TO_CALL_COMPLETE_OBJECT_KEY =
049 "METHOD_TO_CALL_KEYS_COMPLETE_OBJECT_KEY";
050 public static final String USER_SESSION_METHOD_TO_CALL_COMPLETE_MARKER = "_EXITING";
051
052 /**
053 * Individual document families will need to reimplement this according to
054 * their own needs; this version should be good enough to be usable during
055 * initial development.
056 */
057 public Set<String> getDocumentActions(Document document, Person user, Set<String> documentActions) {
058 if (LOG.isDebugEnabled()) {
059 LOG.debug("calling DocumentAuthorizerBase.getDocumentActionFlags for document '"
060 + document.getDocumentNumber()
061 + "'. user '"
062 + user.getPrincipalName()
063 + "'");
064 }
065 if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_EDIT) && !canEdit(document, user)) {
066 documentActions.remove(KRADConstants.KUALI_ACTION_CAN_EDIT);
067 }
068
069 if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_COPY) && !canCopy(document, user)) {
070 documentActions.remove(KRADConstants.KUALI_ACTION_CAN_COPY);
071 }
072
073 if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_CLOSE) && !canClose(document, user)) {
074 documentActions.remove(KRADConstants.KUALI_ACTION_CAN_CLOSE);
075 }
076
077 if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_RELOAD) && !canReload(document, user)) {
078 documentActions.remove(KRADConstants.KUALI_ACTION_CAN_RELOAD);
079 }
080
081 if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_BLANKET_APPROVE) && !canBlanketApprove(document, user)) {
082 documentActions.remove(KRADConstants.KUALI_ACTION_CAN_BLANKET_APPROVE);
083 }
084
085 if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_CANCEL) && !canCancel(document, user)) {
086 documentActions.remove(KRADConstants.KUALI_ACTION_CAN_CANCEL);
087 }
088
089 if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_RECALL) && !canRecall(document, user)) {
090 documentActions.remove(KRADConstants.KUALI_ACTION_CAN_RECALL);
091 }
092
093 if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_SAVE) && !canSave(document, user)) {
094 documentActions.remove(KRADConstants.KUALI_ACTION_CAN_SAVE);
095 }
096
097 if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_ROUTE) && !canRoute(document, user)) {
098 documentActions.remove(KRADConstants.KUALI_ACTION_CAN_ROUTE);
099 }
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 }