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 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 }