001/**
002 * Copyright 2005-2018 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 */
016package org.kuali.rice.kns.document.authorization;
017
018import org.apache.commons.logging.Log;
019import org.apache.commons.logging.LogFactory;
020import org.kuali.rice.kew.api.KewApiConstants;
021import org.kuali.rice.kew.api.KewApiServiceLocator;
022import org.kuali.rice.kew.api.WorkflowDocument;
023import org.kuali.rice.kew.api.action.ActionType;
024import org.kuali.rice.kew.api.doctype.ProcessDefinition;
025import org.kuali.rice.kew.api.doctype.RoutePath;
026import org.kuali.rice.kew.api.document.node.RouteNodeInstance;
027import org.kuali.rice.kim.api.KimConstants;
028import org.kuali.rice.kim.api.identity.Person;
029import org.kuali.rice.kns.bo.authorization.BusinessObjectAuthorizerBase;
030import org.kuali.rice.krad.document.Document;
031import org.kuali.rice.krad.document.DocumentRequestAuthorizationCache;
032import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
033import org.kuali.rice.krad.util.KRADConstants;
034
035import java.util.Collections;
036import java.util.HashMap;
037import java.util.List;
038import java.util.Map;
039import java.util.Set;
040
041/**
042 * DocumentAuthorizer containing common, reusable document-level authorization
043 * code.
044 *
045 * @deprecated Use {@link org.kuali.rice.krad.document.DocumentAuthorizerBase}.
046 */
047@Deprecated
048public class DocumentAuthorizerBase extends BusinessObjectAuthorizerBase implements DocumentAuthorizer {
049    protected static Log LOG = LogFactory.getLog(DocumentAuthorizerBase.class);
050
051    public static final String PRE_ROUTING_ROUTE_NAME = "PreRoute";
052    public static final String EDIT_MODE_DEFAULT_TRUE_VALUE = "TRUE";
053    public static final String USER_SESSION_METHOD_TO_CALL_OBJECT_KEY = "METHOD_TO_CALL_KEYS_METHOD_OBJECT_KEY";
054    public static final String USER_SESSION_METHOD_TO_CALL_COMPLETE_OBJECT_KEY =
055            "METHOD_TO_CALL_KEYS_COMPLETE_OBJECT_KEY";
056    public static final String USER_SESSION_METHOD_TO_CALL_COMPLETE_MARKER = "_EXITING";
057
058    /**
059     * Individual document families will need to reimplement this according to
060     * their own needs; this version should be good enough to be usable during
061     * initial development.
062     */
063    public Set<String> getDocumentActions(Document document, Person user, Set<String> documentActions) {
064        if (LOG.isDebugEnabled()) {
065            LOG.debug("calling DocumentAuthorizerBase.getDocumentActionFlags for document '"
066                    + document.getDocumentNumber()
067                    + "'. user '"
068                    + user.getPrincipalName()
069                    + "'");
070        }
071        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_EDIT) && !canEdit(document, user)) {
072            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_EDIT);
073        }
074
075        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_COPY) && !canCopy(document, user)) {
076            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_COPY);
077        }
078
079        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_CLOSE) && !canClose(document, user)) {
080            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_CLOSE);
081        }
082
083        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_RELOAD) && !canReload(document, user)) {
084            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_RELOAD);
085        }
086
087        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_BLANKET_APPROVE) && !canBlanketApprove(document, user)) {
088            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_BLANKET_APPROVE);
089        }
090
091        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_CANCEL) && !canCancel(document, user)) {
092            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_CANCEL);
093        }
094
095        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_RECALL) && !canRecall(document, user)) {
096            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_RECALL);
097        }
098
099        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_SAVE) && !canSave(document, user)) {
100            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_SAVE);
101        }
102
103        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_ROUTE) && !canRoute(document, user)) {
104            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_ROUTE);
105        }
106
107        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_ACKNOWLEDGE) && !canAcknowledge(document, user)) {
108            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_ACKNOWLEDGE);
109        }
110
111        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_FYI) && !canFyi(document, user)) {
112            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_FYI);
113        }
114
115        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_APPROVE) && !canApprove(document, user)) {
116            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_APPROVE);
117        }
118
119        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_DISAPPROVE) && !canDisapprove(document, user)) {
120            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_DISAPPROVE);
121        }
122
123        if (!canSendAnyTypeAdHocRequests(document, user)) {
124            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_ADD_ADHOC_REQUESTS);
125            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_SEND_ADHOC_REQUESTS);
126            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_SEND_NOTE_FYI);
127        }
128
129        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_SEND_NOTE_FYI) && !canSendNoteFyi(document, user)) {
130            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_SEND_NOTE_FYI);
131        }
132
133        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_ANNOTATE) && !canAnnotate(document, user)) {
134            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_ANNOTATE);
135        }
136
137        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_EDIT_DOCUMENT_OVERVIEW) && !canEditDocumentOverview(
138                document, user)) {
139            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_EDIT_DOCUMENT_OVERVIEW);
140        }
141
142        if (documentActions.contains(KRADConstants.KUALI_ACTION_PERFORM_ROUTE_REPORT) && !canPerformRouteReport(document,
143                user)) {
144            documentActions.remove(KRADConstants.KUALI_ACTION_PERFORM_ROUTE_REPORT);
145        }
146
147        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_SUPER_USER_TAKE_ACTION) && !canSuperUserTakeAction(document, user)) {
148            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_SUPER_USER_TAKE_ACTION);
149        }
150
151        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_SUPER_USER_APPROVE) && !canSuperUserApprove(document, user)) {
152            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_SUPER_USER_APPROVE);
153        }
154
155        if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_SUPER_USER_DISAPPROVE) && !canSuperUserDisapprove(document, user)) {
156            documentActions.remove(KRADConstants.KUALI_ACTION_CAN_SUPER_USER_DISAPPROVE);
157        }
158
159        return documentActions;
160    }
161
162    public boolean canInitiate(String documentTypeName, Person user) {
163        String nameSpaceCode = KRADConstants.KUALI_RICE_SYSTEM_NAMESPACE;
164        Map<String, String> permissionDetails = new HashMap<String, String>();
165        permissionDetails.put(KimConstants.AttributeConstants.DOCUMENT_TYPE_NAME, documentTypeName);
166        return getPermissionService().isAuthorizedByTemplate(user.getPrincipalId(), nameSpaceCode,
167                KimConstants.PermissionTemplateNames.INITIATE_DOCUMENT, permissionDetails,
168                Collections.<String, String>emptyMap());
169    }
170
171    public boolean canEdit(Document document, Person user) {
172        // KULRICE-7864: document can be editable on adhoc route for completion 
173        return document.getDocumentHeader().getWorkflowDocument().isCompletionRequested()
174                || isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE, KimConstants.PermissionTemplateNames.EDIT_DOCUMENT, user.getPrincipalId());
175    }
176
177    public boolean canAnnotate(Document document, Person user) {
178        return canEdit(document, user);
179    }
180
181    public boolean canReload(Document document, Person user) {
182        return true;
183    }
184
185    public boolean canClose(Document document, Person user) {
186        return true;
187    }
188
189    public boolean canSave(Document document, Person user) {
190        return isAuthorizedByTemplate(document, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE,
191                KimConstants.PermissionTemplateNames.SAVE_DOCUMENT, user.getPrincipalId());
192    }
193
194    public boolean canRoute(Document document, Person user) {
195        return isAuthorizedByTemplate(document, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE,
196                KimConstants.PermissionTemplateNames.ROUTE_DOCUMENT, user.getPrincipalId());
197    }
198
199    public boolean canCancel(Document document, Person user) {
200        // KULRICE-8762: CANCEL button should be enabled for a person who is doing COMPLETE action 
201        boolean isCompletionRequested = document.getDocumentHeader().getWorkflowDocument().isCompletionRequested();
202        return isCompletionRequested || isAuthorizedByTemplate(document, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE,
203                KimConstants.PermissionTemplateNames.CANCEL_DOCUMENT, user.getPrincipalId());
204    }
205
206    public boolean canRecall(Document document, Person user) {
207        return KewApiServiceLocator.getWorkflowDocumentActionsService().determineValidActions(document.getDocumentNumber(), user.getPrincipalId()).getValidActions().contains(ActionType.RECALL);
208    }
209
210    public boolean canCopy(Document document, Person user) {
211        return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
212                KimConstants.PermissionTemplateNames.COPY_DOCUMENT, user.getPrincipalId());
213    }
214
215    public boolean canPerformRouteReport(Document document, Person user) {
216        return true;
217    }
218
219    public boolean canBlanketApprove(Document document, Person user) {
220        return isAuthorizedByTemplate(document, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE,
221                KimConstants.PermissionTemplateNames.BLANKET_APPROVE_DOCUMENT, user.getPrincipalId());
222    }
223
224    public boolean canApprove(Document document, Person user) {
225        return canTakeRequestedAction(document, KewApiConstants.ACTION_REQUEST_APPROVE_REQ, user);
226    }
227
228    public boolean canDisapprove(Document document, Person user) {
229        return canApprove(document, user);
230    }
231
232    public boolean canSendNoteFyi(Document document, Person user) {
233        return canSendAdHocRequests(document, KewApiConstants.ACTION_REQUEST_FYI_REQ, user);
234    }
235
236    public boolean canFyi(Document document, Person user) {
237        return canTakeRequestedAction(document, KewApiConstants.ACTION_REQUEST_FYI_REQ, user);
238    }
239
240    public boolean canAcknowledge(Document document, Person user) {
241        return canTakeRequestedAction(document, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, user);
242    }
243
244    public boolean canReceiveAdHoc(Document document, Person user, String actionRequestCode) {
245        Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
246        additionalPermissionDetails.put(KimConstants.AttributeConstants.ACTION_REQUEST_CD, actionRequestCode);
247        return isAuthorizedByTemplate(document, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE,
248                KimConstants.PermissionTemplateNames.AD_HOC_REVIEW_DOCUMENT, user.getPrincipalId(),
249                additionalPermissionDetails, Collections.<String, String>emptyMap());
250    }
251
252    public boolean canOpen(Document document, Person user) {
253        return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
254                KimConstants.PermissionTemplateNames.OPEN_DOCUMENT, user.getPrincipalId());
255    }
256
257    public boolean canAddNoteAttachment(Document document, String attachmentTypeCode, Person user) {
258        Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
259        if (attachmentTypeCode != null) {
260            additionalPermissionDetails.put(KimConstants.AttributeConstants.ATTACHMENT_TYPE_CODE, attachmentTypeCode);
261        }
262        return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
263                KimConstants.PermissionTemplateNames.ADD_NOTE_ATTACHMENT, user.getPrincipalId(),
264                additionalPermissionDetails, Collections.<String, String>emptyMap());
265    }
266
267    public boolean canDeleteNoteAttachment(Document document, String attachmentTypeCode, String createdBySelfOnly,
268            Person user) {
269        Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
270        if (attachmentTypeCode != null) {
271            additionalPermissionDetails.put(KimConstants.AttributeConstants.ATTACHMENT_TYPE_CODE, attachmentTypeCode);
272        }
273        additionalPermissionDetails.put(KimConstants.AttributeConstants.CREATED_BY_SELF, createdBySelfOnly);
274        return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
275                KimConstants.PermissionTemplateNames.DELETE_NOTE_ATTACHMENT, user.getPrincipalId(),
276                additionalPermissionDetails, Collections.<String, String>emptyMap());
277    }
278
279    public boolean canViewNoteAttachment(Document document, String attachmentTypeCode, Person user) {
280        Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
281        if (attachmentTypeCode != null) {
282            additionalPermissionDetails.put(KimConstants.AttributeConstants.ATTACHMENT_TYPE_CODE, attachmentTypeCode);
283        }
284        return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
285                KimConstants.PermissionTemplateNames.VIEW_NOTE_ATTACHMENT, user.getPrincipalId(),
286                additionalPermissionDetails, Collections.<String, String>emptyMap());
287    }
288
289    public boolean canViewNoteAttachment(Document document, String attachmentTypeCode, String authorUniversalIdentifier,
290            Person user) {
291        return canViewNoteAttachment(document, attachmentTypeCode, user);
292    }
293
294    public boolean canSendAdHocRequests(Document document, String actionRequestCd, Person user) {
295        Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
296        if (actionRequestCd != null) {
297            additionalPermissionDetails.put(KimConstants.AttributeConstants.ACTION_REQUEST_CD, actionRequestCd);
298        }
299        return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
300                KimConstants.PermissionTemplateNames.SEND_AD_HOC_REQUEST, user.getPrincipalId(),
301                additionalPermissionDetails, Collections.<String, String>emptyMap());
302    }
303
304    public boolean canEditDocumentOverview(Document document, Person user) {
305        return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
306                KimConstants.PermissionTemplateNames.EDIT_DOCUMENT, user.getPrincipalId()) && this.isDocumentInitiator(
307                document, user);
308    }
309
310    public boolean canSendAnyTypeAdHocRequests(Document document, Person user) {
311        if (canSendAdHocRequests(document, KewApiConstants.ACTION_REQUEST_FYI_REQ, user)) {
312            RoutePath routePath = KewApiServiceLocator.getDocumentTypeService().getRoutePathForDocumentTypeName(
313                    document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName());
314            ProcessDefinition processDefinition = routePath.getPrimaryProcess();
315            if (processDefinition != null) {
316                if (processDefinition.getInitialRouteNode() == null) {
317                    return false;
318                }
319            } else {
320                return false;
321            }
322            return true;
323        } else if (canSendAdHocRequests(document, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, user)) {
324            return true;
325        }
326        return canSendAdHocRequests(document, KewApiConstants.ACTION_REQUEST_APPROVE_REQ, user);
327    }
328
329    public boolean canTakeRequestedAction(Document document, String actionRequestCode, Person user) {
330        Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
331        additionalPermissionDetails.put(KimConstants.AttributeConstants.ACTION_REQUEST_CD, actionRequestCode);
332        return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
333                KimConstants.PermissionTemplateNames.TAKE_REQUESTED_ACTION, user.getPrincipalId(),
334                additionalPermissionDetails, Collections.<String, String>emptyMap());
335    }
336
337    /**
338     * {@inheritDoc}
339     */
340    @Override
341    public boolean canSuperUserTakeAction(Document document, Person user) {
342        if (!document.getDocumentHeader().hasWorkflowDocument()) {
343            return false;
344        }
345
346        String principalId = user.getPrincipalId();
347
348        String documentTypeId = document.getDocumentHeader().getWorkflowDocument().getDocumentTypeId();
349        if (KewApiServiceLocator.getDocumentTypeService().isSuperUserForDocumentTypeId(principalId, documentTypeId)) {
350            return true;
351        }
352
353        String documentTypeName = document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
354        List<RouteNodeInstance> routeNodeInstances = document.getDocumentHeader().getWorkflowDocument().getRouteNodeInstances();
355        String documentStatus =  document.getDocumentHeader().getWorkflowDocument().getStatus().getCode();
356        return KewApiServiceLocator.getDocumentTypeService().canSuperUserApproveSingleActionRequest(
357                principalId, documentTypeName, routeNodeInstances, documentStatus);
358    }
359
360    /**
361     * {@inheritDoc}
362     */
363    @Override
364    public boolean canSuperUserApprove(Document document, Person user) {
365        if (!document.getDocumentHeader().hasWorkflowDocument()) {
366            return false;
367        }
368
369        String principalId = user.getPrincipalId();
370
371        String documentTypeId = document.getDocumentHeader().getWorkflowDocument().getDocumentTypeId();
372        if (KewApiServiceLocator.getDocumentTypeService().isSuperUserForDocumentTypeId(principalId, documentTypeId)) {
373            return true;
374        }
375
376        String documentTypeName = document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
377        List<RouteNodeInstance> routeNodeInstances = document.getDocumentHeader().getWorkflowDocument().getRouteNodeInstances();
378        String documentStatus =  document.getDocumentHeader().getWorkflowDocument().getStatus().getCode();
379        return KewApiServiceLocator.getDocumentTypeService().canSuperUserApproveDocument(
380                principalId, documentTypeName, routeNodeInstances, documentStatus);
381    }
382
383    /**
384     * {@inheritDoc}
385     */
386    @Override
387    public boolean canSuperUserDisapprove(Document document, Person user) {
388        if (!document.getDocumentHeader().hasWorkflowDocument()) {
389            return false;
390        }
391
392        String principalId = user.getPrincipalId();
393
394        String documentTypeId = document.getDocumentHeader().getWorkflowDocument().getDocumentTypeId();
395        if (KewApiServiceLocator.getDocumentTypeService().isSuperUserForDocumentTypeId(principalId, documentTypeId)) {
396            return true;
397        }
398
399        String documentTypeName = document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
400        List<RouteNodeInstance> routeNodeInstances = document.getDocumentHeader().getWorkflowDocument().getRouteNodeInstances();
401        String documentStatus =  document.getDocumentHeader().getWorkflowDocument().getStatus().getCode();
402        return KewApiServiceLocator.getDocumentTypeService().canSuperUserDisapproveDocument(
403                principalId, documentTypeName, routeNodeInstances, documentStatus);
404    }
405
406    @Override
407    protected void addPermissionDetails(Object dataObject, Map<String, String> attributes) {
408        super.addPermissionDetails(dataObject, attributes);
409        if (dataObject instanceof Document) {
410            addStandardAttributes((Document) dataObject, attributes);
411        }
412    }
413
414    @Override
415    protected void addRoleQualification(Object dataObject, Map<String, String> attributes) {
416        super.addRoleQualification(dataObject, attributes);
417        if (dataObject instanceof Document) {
418            addStandardAttributes((Document) dataObject, attributes);
419        }
420    }
421
422    protected void addStandardAttributes(Document document, Map<String, String> attributes) {
423        WorkflowDocument wd = document.getDocumentHeader().getWorkflowDocument();
424        attributes.put(KimConstants.AttributeConstants.DOCUMENT_NUMBER, document.getDocumentNumber());
425        attributes.put(KimConstants.AttributeConstants.DOCUMENT_TYPE_NAME, wd.getDocumentTypeName());
426        if (wd.isInitiated() || wd.isSaved()) {
427            attributes.put(KimConstants.AttributeConstants.ROUTE_NODE_NAME, PRE_ROUTING_ROUTE_NAME);
428        } else {
429            attributes.put(KimConstants.AttributeConstants.ROUTE_NODE_NAME,
430                    KRADServiceLocatorWeb.getWorkflowDocumentService().getCurrentRouteNodeNames(wd));
431        }
432        attributes.put(KimConstants.AttributeConstants.ROUTE_STATUS_CODE, wd.getStatus().getCode());
433    }
434
435    protected boolean isDocumentInitiator(Document document, Person user) {
436        WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
437        return workflowDocument.getInitiatorPrincipalId().equalsIgnoreCase(user.getPrincipalId());
438    }
439
440    @Override
441    public void setDocumentRequestAuthorizationCache(
442            DocumentRequestAuthorizationCache documentRequestAuthorizationCache) {
443        // noop
444    }
445}