diff --git a/source/java/org/alfresco/repo/webdav/PutMethod.java b/source/java/org/alfresco/repo/webdav/PutMethod.java index 5087c189c8..0768c40f5f 100644 --- a/source/java/org/alfresco/repo/webdav/PutMethod.java +++ b/source/java/org/alfresco/repo/webdav/PutMethod.java @@ -19,12 +19,7 @@ package org.alfresco.repo.webdav; import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; import java.io.Serializable; import java.nio.charset.Charset; import java.util.HashMap; @@ -34,14 +29,13 @@ import javax.servlet.http.HttpServletResponse; import org.alfresco.model.ContentModel; import org.alfresco.repo.content.encoding.ContentCharsetFinder; +import org.alfresco.service.cmr.lock.LockStatus; import org.alfresco.service.cmr.model.FileExistsException; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileNotFoundException; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.namespace.QName; -import org.alfresco.util.TempFileProvider; -import org.springframework.util.FileCopyUtils; /** * Implements the WebDAV PUT method @@ -55,8 +49,6 @@ public class PutMethod extends WebDAVMethod private String m_strContentType = null; private boolean m_expectHeaderPresent = false; - private File requestBody = null; - /** * Default constructor */ @@ -91,16 +83,8 @@ public class PutMethod extends WebDAVMethod */ protected void parseRequestBody() throws WebDAVServerException { - requestBody = TempFileProvider.createTempFile("webdav_PUT_", ".bin"); - try - { - OutputStream out = new FileOutputStream(requestBody); - FileCopyUtils.copy(m_request.getInputStream(), out); - } - catch (IOException e) - { - throw new WebDAVServerException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e); - } + // Nothing to do in this method, the body contains + // the content it will be dealt with later } /** @@ -156,6 +140,16 @@ public class PutMethod extends WebDAVMethod } } + LockStatus lockSts = getLockService().getLockStatus(contentNodeInfo.getNodeRef()); + String userName = getDAVHelper().getAuthenticationService().getCurrentUserName(); + String owner = (String) getNodeService().getProperty(contentNodeInfo.getNodeRef(), ContentModel.PROP_LOCK_OWNER); + + if (lockSts == LockStatus.LOCKED || (lockSts == LockStatus.LOCK_OWNER && !userName.equals(owner))) + { + // Indicate that the resource is locked + throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED); + } + // Access the content ContentWriter writer = fileFolderService.getWriter(contentNodeInfo.getNodeRef()); // set content properties @@ -166,13 +160,13 @@ public class PutMethod extends WebDAVMethod } else { - String guessedMimetype = getMimetypeService().guessMimetype(getPath()); + String guessedMimetype = getMimetypeService().guessMimetype(contentNodeInfo.getName()); mimetype = guessedMimetype; } writer.setMimetype(mimetype); // Get the input stream from the request data - InputStream is = new FileInputStream(requestBody); + InputStream is = m_request.getInputStream(); is = is.markSupported() ? is : new BufferedInputStream(is); ContentCharsetFinder charsetFinder = getMimetypeService().getContentCharsetFinder(); @@ -185,17 +179,4 @@ public class PutMethod extends WebDAVMethod // Set the response status, depending if the node existed or not m_response.setStatus(created ? HttpServletResponse.SC_CREATED : HttpServletResponse.SC_NO_CONTENT); } - - @Override - protected void cleanup() - { - try - { - requestBody.delete(); - } - catch (Throwable t) - { - logger.error("Failed to delete temp file", t); - } - } } diff --git a/source/java/org/alfresco/repo/webdav/WebDAVMethod.java b/source/java/org/alfresco/repo/webdav/WebDAVMethod.java index bd33ebe81c..f59dbd44cd 100644 --- a/source/java/org/alfresco/repo/webdav/WebDAVMethod.java +++ b/source/java/org/alfresco/repo/webdav/WebDAVMethod.java @@ -18,14 +18,22 @@ */ package org.alfresco.repo.webdav; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -50,11 +58,13 @@ import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.TempFileProvider; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.dom4j.DocumentHelper; import org.dom4j.io.OutputFormat; import org.dom4j.io.XMLWriter; +import org.springframework.util.FileCopyUtils; import org.w3c.dom.Document; import org.xml.sax.Attributes; import org.xml.sax.InputSource; @@ -80,6 +90,9 @@ public abstract class WebDAVMethod protected HttpServletRequest m_request; protected HttpServletResponse m_response; + private File m_requestBody; + private ServletInputStream m_inputStream; + private BufferedReader m_reader; // WebDAV helper @@ -116,21 +129,131 @@ public abstract class WebDAVMethod /** * Set the request/response details * - * @param req HttpServletRequest - * @param resp HttpServletResponse - * @param registry ServiceRegistry - * @param rootNode NodeRef + * @param req + * HttpServletRequest + * @param resp + * HttpServletResponse + * @param registry + * ServiceRegistry + * @param rootNode + * NodeRef */ - public void setDetails(HttpServletRequest req, HttpServletResponse resp, WebDAVHelper davHelper, NodeRef rootNode) + public void setDetails(final HttpServletRequest req, HttpServletResponse resp, WebDAVHelper davHelper, + NodeRef rootNode) { - m_request = req; - m_response = resp; - m_davHelper = davHelper; - m_rootNodeRef = rootNode; + // Wrap the request so that it is 'retryable'. Calls to getInputStream() and getReader() will result in the + // request body being read into an intermediate file. + this.m_request = new HttpServletRequestWrapper(req) + { - m_strPath = WebDAV.getRepositoryPath(req); + @Override + public ServletInputStream getInputStream() throws IOException + { + if (WebDAVMethod.this.m_reader != null) + { + throw new IllegalStateException("Reader in use"); + } + if (WebDAVMethod.this.m_inputStream == null) + { + final FileInputStream in = new FileInputStream(getRequestBodyAsFile(req)); + WebDAVMethod.this.m_inputStream = new ServletInputStream() + { + + @Override + public int read() throws IOException + { + return in.read(); + } + + @Override + public int read(byte b[]) throws IOException + { + return in.read(b); + } + + @Override + public int read(byte b[], int off, int len) throws IOException + { + return in.read(b, off, len); + } + + @Override + public long skip(long n) throws IOException + { + return in.skip(n); + } + + @Override + public int available() throws IOException + { + return in.available(); + } + + @Override + public void close() throws IOException + { + in.close(); + } + + @Override + public void mark(int readlimit) + { + in.mark(readlimit); + } + + @Override + public void reset() throws IOException + { + in.reset(); + } + + @Override + public boolean markSupported() + { + return in.markSupported(); + } + }; + } + + return WebDAVMethod.this.m_inputStream; + } + + @Override + public BufferedReader getReader() throws IOException + { + if (WebDAVMethod.this.m_inputStream != null) + { + throw new IllegalStateException("Input Stream in use"); + } + if (WebDAVMethod.this.m_reader == null) + { + String encoding = req.getCharacterEncoding(); + WebDAVMethod.this.m_reader = new BufferedReader(new InputStreamReader(new FileInputStream( + getRequestBodyAsFile(req)), encoding == null ? "ISO-8859-1" : encoding)); + } + + return WebDAVMethod.this.m_reader; + } + + }; + this.m_response = resp; + this.m_davHelper = davHelper; + this.m_rootNodeRef = rootNode; + + this.m_strPath = WebDAV.getRepositoryPath(req); } - + + private File getRequestBodyAsFile(HttpServletRequest req) throws IOException + { + if (this.m_requestBody == null) + { + this.m_requestBody = TempFileProvider.createTempFile("webdav_" + req.getMethod() + "_", ".bin"); + OutputStream out = new FileOutputStream(this.m_requestBody); + FileCopyUtils.copy(req.getInputStream(), out); + } + return this.m_requestBody; + } + /** * Override and return true if the method is a query method only. The default implementation * returns false. @@ -168,6 +291,10 @@ public abstract class WebDAVMethod { public Object execute() throws Exception { + // Reset the request input stream / reader state + WebDAVMethod.this.m_inputStream = null; + WebDAVMethod.this.m_reader = null; + executeImpl(); return null; } @@ -201,7 +328,19 @@ public abstract class WebDAVMethod } finally { - cleanup(); + // Remove temporary file if created + if (this.m_requestBody != null) + { + try + { + this.m_requestBody.delete(); + this.m_requestBody = null; + } + catch (Throwable t) + { + WebDAVMethod.logger.error("Failed to delete temp file", t); + } + } } } @@ -650,10 +789,6 @@ public abstract class WebDAVMethod return ns.toString(); } - - protected void cleanup() - { - } /** * Checks if write operation can be performed on node. * diff --git a/source/java/org/alfresco/repo/webdav/auth/BaseAuthenticationFilter.java b/source/java/org/alfresco/repo/webdav/auth/BaseAuthenticationFilter.java index a8c2ec5b97..1ca44cebd8 100644 --- a/source/java/org/alfresco/repo/webdav/auth/BaseAuthenticationFilter.java +++ b/source/java/org/alfresco/repo/webdav/auth/BaseAuthenticationFilter.java @@ -19,6 +19,7 @@ package org.alfresco.repo.webdav.auth; import java.io.IOException; +import java.io.Reader; import javax.servlet.ServletContext; import javax.servlet.ServletException; @@ -37,6 +38,8 @@ import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.transaction.TransactionService; import org.apache.commons.logging.Log; +import org.json.JSONException; +import org.json.JSONObject; /** * A base class for authentication filters. Handles management of the session user. @@ -282,5 +285,68 @@ public abstract class BaseAuthenticationFilter * @return Log */ protected abstract Log getLogger(); + + /** + * Handles the login form directly, allowing management of the session user. + * + * @param req + * the request + * @param res + * the response + * @throws IOException + * Signals that an I/O exception has occurred. + * @throws ServletException + * on error + */ + protected void handleLoginForm(HttpServletRequest req, HttpServletResponse res) throws IOException, + ServletException + { + // Invalidate current session + HttpSession session = req.getSession(false); + if (session != null) + { + session.invalidate(); + } + StringBuilder out = new StringBuilder(1024); + Reader in = req.getReader(); + char[] buff = new char[1024]; + int charsRead; + while ((charsRead = in.read(buff)) != -1) + { + out.append(buff, 0, charsRead); + } + in.close(); + try + { + JSONObject json = new JSONObject(out.toString()); + String username = json.getString("username"); + String password = json.getString("password"); + + if (username == null || username.length() == 0) + { + res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Username not specified"); + return; + } + + if (password == null) + { + res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Password not specified"); + return; + } + + authenticationService.authenticate(username, password.toCharArray()); + session = req.getSession(); + createUserEnvironment(session, username, authenticationService.getCurrentTicket(session.getId()), false); + res.setStatus(HttpServletResponse.SC_NO_CONTENT); + } + catch (AuthenticationException e) + { + res.sendError(HttpServletResponse.SC_FORBIDDEN, "Login failed"); + } + catch (JSONException jErr) + { + res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Unable to parse JSON POST body: " + jErr.getMessage()); + } + } } \ No newline at end of file