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.krad.document;
017
018import org.kuali.rice.kew.api.KewApiConstants;
019import org.kuali.rice.kew.api.KewApiServiceLocator;
020import org.kuali.rice.kew.api.WorkflowDocument;
021import org.kuali.rice.kew.api.action.ActionType;
022import org.kuali.rice.kew.api.doctype.ProcessDefinition;
023import org.kuali.rice.kew.api.doctype.RoutePath;
024import org.kuali.rice.kew.api.document.node.RouteNodeInstance;
025import org.kuali.rice.kim.api.KimConstants;
026import org.kuali.rice.kim.api.identity.Person;
027import org.kuali.rice.krad.bo.DataObjectAuthorizerBase;
028import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
029import org.kuali.rice.krad.util.KRADConstants;
030
031import java.util.Collections;
032import java.util.HashMap;
033import java.util.List;
034import java.util.Map;
035
036/**
037 * Default implementation for {@link DocumentAuthorizer} that perform KIM permission checks to authorize the actions
038 *
039 * @author Kuali Rice Team (rice.collab@kuali.org)
040 */
041public class DocumentAuthorizerBase extends DataObjectAuthorizerBase implements DocumentAuthorizer {
042    private static final long serialVersionUID = -5354518767379472681L;
043
044    private DocumentRequestAuthorizationCache documentRequestAuthorizationCache;
045
046    public static final String PRE_ROUTING_ROUTE_NAME = "PreRoute";
047
048    public final boolean canInitiate(String documentTypeName, Person user) {
049        String nameSpaceCode = KRADConstants.KUALI_RICE_SYSTEM_NAMESPACE;
050        Map<String, String> permissionDetails = new HashMap<String, String>();
051        permissionDetails.put(KimConstants.AttributeConstants.DOCUMENT_TYPE_NAME, documentTypeName);
052
053        return getPermissionService().isAuthorizedByTemplate(user.getPrincipalId(), nameSpaceCode,
054                KimConstants.PermissionTemplateNames.INITIATE_DOCUMENT, permissionDetails,
055                Collections.<String, String>emptyMap());
056    }
057
058    public boolean canOpen(Document document, Person user) {
059        return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
060                KimConstants.PermissionTemplateNames.OPEN_DOCUMENT, user.getPrincipalId());
061    }
062
063    public boolean canEdit(Document document, Person user) {
064        return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
065                KimConstants.PermissionTemplateNames.EDIT_DOCUMENT, user.getPrincipalId());
066    }
067
068    public boolean canAnnotate(Document document, Person user) {
069        return canAddNoteAttachment(document, null, user);
070    }
071
072    public boolean canReload(Document document, Person user) {
073        return true;
074    }
075
076    public boolean canClose(Document document, Person user) {
077        return false;
078    }
079
080    public boolean canSave(Document document, Person user) {
081        return isAuthorizedByTemplate(document, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE,
082                KimConstants.PermissionTemplateNames.SAVE_DOCUMENT, user.getPrincipalId());
083    }
084
085    public boolean canRoute(Document document, Person user) {
086        return isAuthorizedByTemplate(document, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE,
087                KimConstants.PermissionTemplateNames.ROUTE_DOCUMENT, user.getPrincipalId());
088    }
089
090    public boolean canCancel(Document document, Person user) {
091        boolean isCompletionRequested = document.getDocumentHeader().getWorkflowDocument().isCompletionRequested();
092
093        return isCompletionRequested || isAuthorizedByTemplate(document, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE,
094                KimConstants.PermissionTemplateNames.CANCEL_DOCUMENT, user.getPrincipalId());
095    }
096
097    public boolean canRecall(Document document, Person user) {
098        return getDocumentRequestAuthorizationCache(document).getWorkflowDocumentInfo().isValidAction(
099                ActionType.RECALL);
100    }
101
102    public boolean canCopy(Document document, Person user) {
103        return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
104                KimConstants.PermissionTemplateNames.COPY_DOCUMENT, user.getPrincipalId());
105    }
106
107    public boolean canPerformRouteReport(Document document, Person user) {
108        return true;
109    }
110
111    public boolean canBlanketApprove(Document document, Person user) {
112        return isAuthorizedByTemplate(document, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE,
113                KimConstants.PermissionTemplateNames.BLANKET_APPROVE_DOCUMENT, user.getPrincipalId());
114    }
115
116    public boolean canApprove(Document document, Person user) {
117        return canTakeRequestedAction(document, KewApiConstants.ACTION_REQUEST_APPROVE_REQ, user);
118    }
119
120    public boolean canDisapprove(Document document, Person user) {
121        return canApprove(document, user);
122    }
123
124    public boolean canSendNoteFyi(Document document, Person user) {
125        return canSendAdHocRequests(document, KewApiConstants.ACTION_REQUEST_FYI_REQ, user);
126    }
127
128    public boolean canFyi(Document document, Person user) {
129        return canTakeRequestedAction(document, KewApiConstants.ACTION_REQUEST_FYI_REQ, user);
130    }
131
132    public boolean canAcknowledge(Document document, Person user) {
133        return canTakeRequestedAction(document, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, user);
134    }
135
136    public boolean canReceiveAdHoc(Document document, Person user, String actionRequestCode) {
137        Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
138        additionalPermissionDetails.put(KimConstants.AttributeConstants.ACTION_REQUEST_CD, actionRequestCode);
139
140        return isAuthorizedByTemplate(document, KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE,
141                KimConstants.PermissionTemplateNames.AD_HOC_REVIEW_DOCUMENT, user.getPrincipalId(),
142                additionalPermissionDetails, null);
143    }
144
145    public boolean canAddNoteAttachment(Document document, String attachmentTypeCode, Person user) {
146        Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
147        if (attachmentTypeCode != null) {
148            additionalPermissionDetails.put(KimConstants.AttributeConstants.ATTACHMENT_TYPE_CODE, attachmentTypeCode);
149        }
150
151        return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
152                KimConstants.PermissionTemplateNames.ADD_NOTE_ATTACHMENT, user.getPrincipalId(),
153                additionalPermissionDetails, null);
154    }
155
156    public boolean canDeleteNoteAttachment(Document document, String attachmentTypeCode,
157            String authorUniversalIdentifier, Person user) {
158        boolean canDeleteNoteAttachment = false;
159
160        Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
161        if (attachmentTypeCode != null) {
162            additionalPermissionDetails.put(KimConstants.AttributeConstants.ATTACHMENT_TYPE_CODE, attachmentTypeCode);
163        }
164
165        // first check permissions that does not restrict on the author
166        additionalPermissionDetails.put(KimConstants.AttributeConstants.CREATED_BY_SELF, "false");
167        canDeleteNoteAttachment = isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
168                KimConstants.PermissionTemplateNames.DELETE_NOTE_ATTACHMENT, user.getPrincipalId(),
169                additionalPermissionDetails, null);
170
171        if (!canDeleteNoteAttachment) {
172            // check for permissions restricted by author
173            additionalPermissionDetails.put(KimConstants.AttributeConstants.CREATED_BY_SELF, "true");
174            canDeleteNoteAttachment = isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
175                    KimConstants.PermissionTemplateNames.DELETE_NOTE_ATTACHMENT, user.getPrincipalId(),
176                    additionalPermissionDetails, null);
177
178            // if permission has been granted user must be the author
179            if (canDeleteNoteAttachment && !authorUniversalIdentifier.equals(user.getPrincipalId())) {
180                canDeleteNoteAttachment = false;
181            }
182        }
183
184        return canDeleteNoteAttachment;
185    }
186
187    public boolean canViewNoteAttachment(Document document, String attachmentTypeCode, Person user) {
188        Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
189        if (attachmentTypeCode != null) {
190            additionalPermissionDetails.put(KimConstants.AttributeConstants.ATTACHMENT_TYPE_CODE, attachmentTypeCode);
191        }
192
193        return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
194                KimConstants.PermissionTemplateNames.VIEW_NOTE_ATTACHMENT, user.getPrincipalId(),
195                additionalPermissionDetails, null);
196    }
197
198    @Deprecated
199    public boolean canViewNoteAttachment(Document document, String attachmentTypeCode, String authorUniversalIdentifier,
200            Person user) {
201        return canViewNoteAttachment(document, attachmentTypeCode, user);
202    }
203
204    public boolean canSendAdHocRequests(Document document, String actionRequestCd, Person user) {
205        Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
206        if (actionRequestCd != null) {
207            additionalPermissionDetails.put(KimConstants.AttributeConstants.ACTION_REQUEST_CD, actionRequestCd);
208        }
209
210        return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
211                KimConstants.PermissionTemplateNames.SEND_AD_HOC_REQUEST, user.getPrincipalId(),
212                additionalPermissionDetails, null);
213    }
214
215    public boolean canEditDocumentOverview(Document document, Person user) {
216        return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
217                KimConstants.PermissionTemplateNames.EDIT_DOCUMENT, user.getPrincipalId()) && this.isDocumentInitiator(
218                document, user);
219    }
220
221    public boolean canSendAnyTypeAdHocRequests(Document document, Person user) {
222        if (canSendAdHocRequests(document, KewApiConstants.ACTION_REQUEST_FYI_REQ, user)) {
223            RoutePath routePath = KewApiServiceLocator.getDocumentTypeService().getRoutePathForDocumentTypeName(
224                    document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName());
225            ProcessDefinition processDefinition = routePath.getPrimaryProcess();
226            if (processDefinition != null) {
227                if (processDefinition.getInitialRouteNode() == null) {
228                    return false;
229                }
230            } else {
231                return false;
232            }
233
234            return true;
235        } else if (canSendAdHocRequests(document, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, user)) {
236            return true;
237        }
238
239        return canSendAdHocRequests(document, KewApiConstants.ACTION_REQUEST_APPROVE_REQ, user);
240    }
241
242    public boolean canTakeRequestedAction(Document document, String actionRequestCode, Person user) {
243        Map<String, String> additionalPermissionDetails = new HashMap<String, String>();
244        additionalPermissionDetails.put(KimConstants.AttributeConstants.ACTION_REQUEST_CD, actionRequestCode);
245
246        return isAuthorizedByTemplate(document, KRADConstants.KNS_NAMESPACE,
247                KimConstants.PermissionTemplateNames.TAKE_REQUESTED_ACTION, user.getPrincipalId(),
248                additionalPermissionDetails, null);
249    }
250
251    public boolean canSuperUserTakeAction(Document document, Person user) {
252        if (!document.getDocumentHeader().hasWorkflowDocument()) {
253            return false;
254        }
255
256        String principalId = user.getPrincipalId();
257
258        String documentTypeId = document.getDocumentHeader().getWorkflowDocument().getDocumentTypeId();
259        if (KewApiServiceLocator.getDocumentTypeService().isSuperUserForDocumentTypeId(principalId, documentTypeId)) {
260            return true;
261        }
262
263        String documentTypeName = document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
264        List<RouteNodeInstance> routeNodeInstances = document.getDocumentHeader().getWorkflowDocument().getRouteNodeInstances();
265        String documentStatus =  document.getDocumentHeader().getWorkflowDocument().getStatus().getCode();
266        return KewApiServiceLocator.getDocumentTypeService().canSuperUserApproveSingleActionRequest(
267                principalId, documentTypeName, routeNodeInstances, documentStatus);
268    }
269
270    public boolean canSuperUserApprove(Document document, Person user) {
271        if (!document.getDocumentHeader().hasWorkflowDocument()) {
272            return false;
273        }
274
275        String principalId = user.getPrincipalId();
276
277        String documentTypeId = document.getDocumentHeader().getWorkflowDocument().getDocumentTypeId();
278        if (KewApiServiceLocator.getDocumentTypeService().isSuperUserForDocumentTypeId(principalId, documentTypeId)) {
279            return true;
280        }
281
282        String documentTypeName = document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
283        List<RouteNodeInstance> routeNodeInstances = document.getDocumentHeader().getWorkflowDocument().getRouteNodeInstances();
284        String documentStatus =  document.getDocumentHeader().getWorkflowDocument().getStatus().getCode();
285        return KewApiServiceLocator.getDocumentTypeService().canSuperUserApproveDocument(
286                principalId, documentTypeName, routeNodeInstances, documentStatus);
287    }
288
289    public boolean canSuperUserDisapprove(Document document, Person user) {
290        if (!document.getDocumentHeader().hasWorkflowDocument()) {
291            return false;
292        }
293
294        String principalId = user.getPrincipalId();
295
296        String documentTypeId = document.getDocumentHeader().getWorkflowDocument().getDocumentTypeId();
297        if (KewApiServiceLocator.getDocumentTypeService().isSuperUserForDocumentTypeId(principalId, documentTypeId)) {
298            return true;
299        }
300
301        String documentTypeName = document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
302        List<RouteNodeInstance> routeNodeInstances = document.getDocumentHeader().getWorkflowDocument().getRouteNodeInstances();
303        String documentStatus =  document.getDocumentHeader().getWorkflowDocument().getStatus().getCode();
304        return KewApiServiceLocator.getDocumentTypeService().canSuperUserDisapproveDocument(
305                principalId, documentTypeName, routeNodeInstances, documentStatus);
306    }
307
308    @Override
309    protected void addPermissionDetails(Object dataObject, Map<String, String> attributes) {
310        super.addPermissionDetails(dataObject, attributes);
311
312        if (dataObject instanceof Document) {
313            addStandardAttributes((Document) dataObject, attributes);
314        }
315    }
316
317    @Override
318    protected void addRoleQualification(Object dataObject, Map<String, String> attributes) {
319        super.addRoleQualification(dataObject, attributes);
320
321        if (dataObject instanceof Document) {
322            addStandardAttributes((Document) dataObject, attributes);
323        }
324    }
325
326    protected void addStandardAttributes(Document document, Map<String, String> attributes) {
327        WorkflowDocument wd = document.getDocumentHeader().getWorkflowDocument();
328        attributes.put(KimConstants.AttributeConstants.DOCUMENT_NUMBER, document.getDocumentNumber());
329        attributes.put(KimConstants.AttributeConstants.DOCUMENT_TYPE_NAME, wd.getDocumentTypeName());
330
331        if (wd.isInitiated() || wd.isSaved()) {
332            attributes.put(KimConstants.AttributeConstants.ROUTE_NODE_NAME, PRE_ROUTING_ROUTE_NAME);
333        } else {
334            attributes.put(KimConstants.AttributeConstants.ROUTE_NODE_NAME,
335                    KRADServiceLocatorWeb.getWorkflowDocumentService().getCurrentRouteNodeNames(wd));
336        }
337
338        attributes.put(KimConstants.AttributeConstants.ROUTE_STATUS_CODE, wd.getStatus().getCode());
339    }
340
341    protected boolean isDocumentInitiator(Document document, Person user) {
342        WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
343
344        return workflowDocument.getInitiatorPrincipalId().equalsIgnoreCase(user.getPrincipalId());
345    }
346
347    protected DocumentRequestAuthorizationCache getDocumentRequestAuthorizationCache(Document document) {
348        if (this.documentRequestAuthorizationCache == null) {
349            this.documentRequestAuthorizationCache = new DocumentRequestAuthorizationCache();
350        }
351
352        if (this.documentRequestAuthorizationCache.getWorkflowDocumentInfo() == null) {
353            this.documentRequestAuthorizationCache.createWorkflowDocumentInfo(
354                    document.getDocumentHeader().getWorkflowDocument());
355        }
356
357        return this.documentRequestAuthorizationCache;
358    }
359
360    /**
361     * {@inheritDoc}
362     */
363    @Override
364    public void setDocumentRequestAuthorizationCache(
365            DocumentRequestAuthorizationCache documentRequestAuthorizationCache) {
366         this.documentRequestAuthorizationCache = documentRequestAuthorizationCache;
367    }
368}