001/** 002 * Copyright 2005-2017 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.kew.notes.web; 017 018import org.apache.log4j.Logger; 019import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator; 020import org.kuali.rice.kew.api.WorkflowRuntimeException; 021import org.kuali.rice.kew.doctype.SecuritySession; 022import org.kuali.rice.kew.notes.Attachment; 023import org.kuali.rice.kew.notes.service.NoteService; 024import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue; 025import org.kuali.rice.kew.service.KEWServiceLocator; 026import org.kuali.rice.kew.api.KewApiConstants; 027import org.kuali.rice.krad.UserSession; 028import org.kuali.rice.krad.util.KRADConstants; 029import org.springframework.core.io.Resource; 030 031import javax.servlet.ServletException; 032import javax.servlet.http.HttpServlet; 033import javax.servlet.http.HttpServletRequest; 034import javax.servlet.http.HttpServletResponse; 035import java.io.BufferedInputStream; 036import java.io.BufferedOutputStream; 037import java.io.File; 038import java.io.FileInputStream; 039import java.io.IOException; 040import java.io.OutputStream; 041 042 043 044 045/** 046 * A servlet which can be used to retrieve attachments from Notes. 047 * 048 * @author Kuali Rice Team (rice.collab@kuali.org) 049 */ 050public class AttachmentServlet extends HttpServlet { 051 052 private static final long serialVersionUID = -1918858512573502697L; 053 public static final String ATTACHMENT_ID_KEY = "attachmentId"; 054 055 // TODO This should probably be put into KewApiConstants when contributed back 056 // to Rice 1.0.3 057 private static final Logger LOG = Logger.getLogger(AttachmentServlet.class); 058 059 @Override 060 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 061 String attachmentId = request.getParameter(ATTACHMENT_ID_KEY); 062 if (attachmentId == null) { 063 throw new ServletException("No 'attachmentId' was specified."); 064 } 065 066 boolean secureChecks = false; 067 String secureAttachmentsParam = null; 068 try { 069 secureAttachmentsParam = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(KewApiConstants.KEW_NAMESPACE, "All", KewApiConstants.SECURE_ATTACHMENTS_PARAM); 070 } catch (Exception e) { 071 LOG.info("Attempted to retrieve parameter value, but could not. Defaulting to unsecured attachment retrieval. " + e.getMessage()); 072 } 073 if (secureAttachmentsParam != null && secureAttachmentsParam.equals("Y")) { 074 secureChecks = true; 075 } 076 try { 077 UserSession userSession = (UserSession) request.getSession().getAttribute(KRADConstants.USER_SESSION_KEY); 078 if (userSession != null) {// If we can get a valid userSession object off the Http request... 079 080 NoteService noteService = KEWServiceLocator.getNoteService(); 081 Attachment attachment = noteService.findAttachment(attachmentId); 082 Resource attachmentResource = noteService.findAttachmentResource(attachment); 083 084 DocumentRouteHeaderValue routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(noteService.getNoteByNoteId(attachment.getNoteId()).getDocumentId()); 085 086 if(!secureChecks || routeHeader != null){// If we can get a valid routeHeader based on the requested attachment ID 087 boolean authorized = KEWServiceLocator.getDocumentSecurityService().routeLogAuthorized(userSession.getPrincipalId(), routeHeader, new SecuritySession(userSession.getPrincipalId())); 088 boolean customAttributeAuthorized = false; 089 if(routeHeader.getCustomNoteAttribute() != null){ 090 routeHeader.getCustomNoteAttribute().setUserSession(userSession); 091 customAttributeAuthorized = routeHeader.getCustomNoteAttribute().isAuthorizedToRetrieveAttachments(); 092 } 093 if(!secureChecks || (authorized && customAttributeAuthorized)){//If this user can see this document, they can get the attachment(s) 094 response.setContentLength((int)attachmentResource.contentLength()); 095 response.setContentType(attachment.getMimeType()); 096 response.setHeader("Content-disposition", "attachment; filename=\"" + attachment.getFileName() + "\""); 097 BufferedInputStream inputStream = new BufferedInputStream(attachmentResource.getInputStream()); 098 OutputStream outputStream = new BufferedOutputStream(response.getOutputStream()); 099 100 try { 101 int c; 102 while ((c = inputStream.read()) != -1) { 103 outputStream.write(c); 104 } 105 } finally { 106 inputStream.close(); 107 } 108 outputStream.close(); 109 } else {// Throw a forbidden page back, they were not approved by DocumentSecurityService 110 LOG.error("Attempt to access attachmentId:"+ attachmentId + " from documentId:" + routeHeader.getDocumentId() + " from unauthorized user: " + userSession.getPrincipalId()); 111 response.sendError(HttpServletResponse.SC_FORBIDDEN); 112 return; 113 } 114 } else {// Throw a not found, couldn't get a valid routeHeader 115 LOG.error("Caught Null Pointer trying to determine routeHeader for requested attachmentId:" + attachmentId); 116 response.sendError(HttpServletResponse.SC_NOT_FOUND); 117 return; 118 } 119 } else {// Throw a bad request, we couldn't find a valid user session 120 LOG.error("Attempt to access attachmentId:" + attachmentId + " with invalid UserSession"); 121 response.sendError(HttpServletResponse.SC_BAD_REQUEST); 122 return; 123 } 124 } catch (Exception e) {// Catch any error, log it. Send a not found, and throw up the exception. 125 LOG.error("Problem retrieving requested attachmentId:" + attachmentId, e); 126 throw new WorkflowRuntimeException(e); 127 } 128 } 129 @Override 130 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 131 doPost(request, response); 132 } 133 134}