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 }