mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
43944: Fixes: ALF-16090: fixes view mode for control param showTime. 43964: Fixes: ALF-14758. Adds distinct styling for menus nested 4 levels or deeper to prevent confusion if there's an overlap. 44029: MNT-180 - Clone for Hotfix: Word document on Windows via CIFS becomes locked (Read Only) when network drops temporarily 44040: Merged V3.4-BUF-GIX (3.4.12) to V4.1-BUG-FIX (4.1.3) 44039: Minor changes to TransformerDebug to make output more readable when there are exceptions. - NPE when there is no exception message 44046: MERGE DEV to V4.1-BUG-FIX ALF-16562 : CIFS: Excel document version history lost after saving content in Excel:mac 2011 on Mac Mountain Lion 44115: Changes to standalone file state cache access mode checks to bring them into line with the clustered file state cache. 44160: Fix for ALF-13129, checks to see if the child association already exists on the versioned node. If it exists it doesn't add it again. 44239: ALF-16977: InstallerBuilder 8.5.1 2012-11-29 with layout fix from Bitrock 44319: Latest installer translations from Gloria 44343: Merged V4.1 (4.1.2) to V4.1-BUG-FIX (4.1.3) 44339: ALF-17070: Merged to V4.1 (4.1.2) from V4.1-BUG-FIX (3.4.12) << Regression introduced into 4.0.2 on 12/4/12 r35201 >> 44337: Merged DEV to V3.4-BUG-FIX (3.4.12) 44297: ALF-16935: wcm/avm file picker fails to render selection from folders navigation only works with 127.0.0.1 url - Fix for regression from ALF-11956, connected with setting titles for file picker controls 44316: Merged DEV to V4.1 44094: ALF-16794: CLONE - Webdav: Version history lost after editing content with Mac Word 2011 in Finder Add WebDAV MOVE handling for case when backup is enabled in Mac 2011 Word 44285: ALF-16794: CLONE - Webdav: Version history lost after editing content with Mac Word 2011 in Finder Handle Mac 2011 Word backup in scope of RenameShuffle 44312: Part 3 for ALF-16895 SOLR: Cannot find files after restart and reindex solr - fix incremental cache state to cope with duplicate leaf/aux doc entries. 44283: Encoding fix by David Webster 44275: Part 2 for ALF-16895 SOLR: Cannot find files after restart and reindex solr - fix initial cache state to cope with duplicate leaf/aux doc entries. 44252: Russian fix from Gloria 44200: Probable fix for ALF-16895 SOLR: Cannot find files after restart and reindex solr - still difficult to reproduce 44149: Merged HEAD to V4.1 44037: ALF-16947: prevent dependency to web-framework-commons war to be transitive: this artifact is not generated in Ant build 44039: Version in parent-pom was not changed properly when deploying to Maven repo 44142: ITALIAN: Translation update based on EN r43623, fixes ALF-16609 44107: ALF-16016, ALF-15991, ALF-16180: Russian fixes by Gloria 44078: ALF-16620: Out of memory Error applying CopiedFromAspectPatch - CopiedFromAspectPatch.WorkProvider.getNextWork() was fetching discrete managable chunks - and then blowing up as it continually fetched into the same in-memory HashSet! 44404: Merged DEV to V4.1-BUG-FIX 44378: ALF-16791 : resource bundle deployement for localization does not work with the dynamic approach 1. Split out MessageService message lookup methods into new interface MessageLookup that lives in DataModel 2. Added a simple implementation for SOLR to use 3. Made M2Label look up model labels via a supplied MessageLookup argument 4. Make DictionaryService extend MessageLookup so that it's easy to find a MessageLookup if you've got a DictionaryService 5. Accounted for interface changes throughout. 44421: ALF-17114: Merged V3.4-BUG-FIX (3.4.12) to V4.1-BUG-FIX (4.1.3) 44419: ALF-17045 If GhostScript is not installed, deletion of content is not working - Not just Ghostscript but any thumbnail failure 44422: ALF-16123: "CheckOutCheckInService.checkout fails with DuplicateChildNodeNameException if no working copy label message found in current locale" 44424: Merged V4.1 (4.1.2) to V4.1-BUG-FIX (4.1.3) RECORD ONLY 44423: ALF-17114: Merged V4.1-BUG-FIX (4.1.3) to V4.1 (4.1.2) - got the wrong branch 44421: ALF-17114: Merged V3.4-BUG-FIX (3.4.12) to V4.1-BUG-FIX (4.1.3) 44419: ALF-17045 If GhostScript is not installed, deletion of content is not working - Not just Ghostscript but any thumbnail failure 44447: Merged V4.0.2 (4.0.0.22) to V4.1-BUG-FIX (4.1.3) RECORD ONLY << Recording this as RECORD ONLY as it turns out the DEV code came form V4.1-BUG-FIX r42431 >> 44435: Merged DEV to V4.0.2 (4.0.2.22) 44429: MNT-232: Upgrade from 3.4.9 to 4.0.2 - FAILED - Initialize rootRefs in the property definition to prevent NPE. 44468: Merged V3.4-PATCHES to V4.1-BUG-FIX MNT-211 (Still needs implementing on 4.1) 44470: Fixes: ALF-16878 - don't use IE8's native JSON stringify method. 44511: ALF-16791: Added missing class. 44519: ALF-16791: Fixed broken unit tests 44541: Fix for ALF-17151 SOLR - add support to disable permission checks 44542: MNT-211 Re-implement on 4.1 44548: ALF-16791: Fixed broken SOLR 44559: ALF-17075: "Exporting and importing null MLText values does not work." 44577: Final part for ALF-16558 SOLR tracking does not do incremental updates but one single chunk - fixed code so SolrSearchers are held for as little time as possible 44590: ALF-14523 (Share - Metadata constraint on workflow creation) 44594: ALF-16310: "Calling CancelCheckout() on the original document deletes the document." 44596: ALF-17075: "Exporting and importing null MLText values does not work." - change test name to something more meaningful 44599: ALF-16310: "Calling CancelCheckout() on the original document deletes the document." 44600: ALF-16791: Another omission not covered by unit tests 44603: ALF-14201: upgrade activiti to 5.7-20121211 44605: Added missing vti.server.url.path.prefix property required by commit 43471 Missing due to cherry picked commit, this is implemented as part of 39309 on HEAD. 44606: ALF-14201: upgrade activiti to 5.7-20121211 in Maven poms 44613: ALF-13690 (Share - It's possible to delete site groups via the UI) 44618: ALF-16939: "Error "importStatus.batchWeight is undefined" is thrown when Bulk Importer status webscript is run for XML format" 44621: Merged PATCHES/V4.1.1 to V4.1-BUG-FIX 44620: MNT-247: Merged DEV to PATCHES/V4.1.1 with corrections 44526: ALF-16964: Share alfrescoCookie connector fails when alfresco.authentication.allowGuestLogin=false, use case proxy between share and alfresco Check if external authentication is active in BaseServlet 44628: Solution for ALF-3780 - Dashboard settings not deleted for deleted user. Initial implementation by Dmitry Velichkevich. Surf user config folder and user Surf dynamic component references are removed when user node is deleted via a Delete Node policy. 44632: addition of validation of NetworkFile isClosed property. 44648: Merge V3.4-BUG-FIX to V4.1-BUG-FIX (4.1.3) 44566: ALF-17164: Add SVN revision in version.properties when building in continuous mode 44602: ALF-17164: adding the SCM revision in version.build so that it is displayed also, sneak in the SVN path, so that tracability is complete 44650: BDE-111: Stop creating installers in parallel, it fails on pbld02. Also, revert to zip compression to gain build time 44651: ALF-14348 (Unable to update external blog configuration details) 44654: Merged DEV to V4.1-BUG-FIX 44614: ALF-17119: Possible UI bug - "$$" chars added to permissions for IMAP Attachments folder Added a message bundles for FullControll access role. 44655: Merged DEV to V4.1-BUG-FIX 44593: ALF-14154: Encoding problem when open a file via webdav on Windows XP Ignore user credentials for the OPTIONS request. 44612: ALF-14154 : Encoding problem when open a file via webdav on Windows XP Ignore user credentials for the OPTIONS request. 44666: ALF-12001: Privacy: blog activities - activity is seen for draft blogs - Wrong node was being used for access checks - Fix by Andrey Chernov 44671: Merged V3.4-BUG-FIX to V4.1-BUG-FIX 43939: ALF-17197 / ALF-16917: Merged PATCHES/V3.4.11 to V3.4-BUG-FIX 43896: MNT-198: Activity feeds get not generated in private sites for added files if username in LDAP-AD contains uppercase letters - Now we can cope with a runAs where the username is in the wrong case 44296: ALF-17203 / ALF-17201 / MNT-216 : error saving versionable word documents git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@44675 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
496 lines
19 KiB
Java
496 lines
19 KiB
Java
/*
|
|
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
|
*
|
|
* This file is part of Alfresco
|
|
*
|
|
* Alfresco is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Alfresco is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package org.alfresco.web.app.servlet;
|
|
|
|
import java.io.IOException;
|
|
import java.io.PrintWriter;
|
|
import java.net.URLEncoder;
|
|
import java.util.ArrayList;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import java.util.StringTokenizer;
|
|
|
|
import javax.faces.context.FacesContext;
|
|
import javax.servlet.ServletContext;
|
|
import javax.servlet.ServletException;
|
|
import javax.servlet.http.HttpServlet;
|
|
import javax.servlet.http.HttpServletRequest;
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
|
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
|
import org.alfresco.repo.tenant.TenantService;
|
|
import org.alfresco.service.ServiceRegistry;
|
|
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.NodeRef;
|
|
import org.alfresco.service.cmr.repository.NodeService;
|
|
import org.alfresco.service.cmr.search.SearchService;
|
|
import org.alfresco.service.cmr.security.AccessStatus;
|
|
import org.alfresco.service.cmr.security.PermissionService;
|
|
import org.alfresco.service.namespace.NamespaceService;
|
|
import org.alfresco.web.app.Application;
|
|
import org.alfresco.web.bean.LoginOutcomeBean;
|
|
import org.alfresco.web.bean.repository.Repository;
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.LogFactory;
|
|
import org.springframework.extensions.surf.util.URLDecoder;
|
|
import org.springframework.web.context.WebApplicationContext;
|
|
import org.springframework.web.context.support.WebApplicationContextUtils;
|
|
import org.springframework.web.jsf.FacesContextUtils;
|
|
|
|
|
|
/**
|
|
* Base servlet class containing useful constant values and common methods for Alfresco servlets.
|
|
*
|
|
* @author Kevin Roast
|
|
*/
|
|
public abstract class BaseServlet extends HttpServlet
|
|
{
|
|
private static final long serialVersionUID = -826295358696861789L;
|
|
|
|
public static final String FACES_SERVLET = "/faces";
|
|
public static final String KEY_STORE = "store";
|
|
public static final String KEY_ROOT_PATH = "rootPath";
|
|
|
|
/** an existing Ticket can be passed to most servlet for non-session based authentication */
|
|
private static final String ARG_TICKET = "ticket";
|
|
|
|
/** forcing guess access is available on most servlets */
|
|
private static final String ARG_GUEST = "guest";
|
|
|
|
private static final String MSG_ERROR_PERMISSIONS = "error_permissions";
|
|
|
|
/** list of valid JSPs for redirect after a clean login */
|
|
// TODO: make this list configurable
|
|
private static Set<String> validRedirectJSPs = new HashSet<String>();
|
|
static
|
|
{
|
|
validRedirectJSPs.add("/jsp/browse/browse.jsp");
|
|
validRedirectJSPs.add("/jsp/admin/admin-console.jsp");
|
|
validRedirectJSPs.add("/jsp/admin/avm-console.jsp");
|
|
validRedirectJSPs.add("/jsp/admin/node-browser.jsp");
|
|
validRedirectJSPs.add("/jsp/admin/store-browser.jsp");
|
|
validRedirectJSPs.add("/jsp/users/user-console.jsp");
|
|
validRedirectJSPs.add("/jsp/categories/categories.jsp");
|
|
validRedirectJSPs.add("/jsp/dialog/about.jsp");
|
|
validRedirectJSPs.add("/jsp/search/advanced-search.jsp");
|
|
validRedirectJSPs.add("/jsp/admin/system-info.jsp");
|
|
validRedirectJSPs.add("/jsp/forums/forums.jsp");
|
|
validRedirectJSPs.add("/jsp/users/users.jsp");
|
|
validRedirectJSPs.add("/jsp/trashcan/trash-list.jsp");
|
|
}
|
|
|
|
private static Log logger = LogFactory.getLog(BaseServlet.class);
|
|
|
|
|
|
/**
|
|
* Return the ServiceRegistry helper instance
|
|
*
|
|
* @param sc ServletContext
|
|
*
|
|
* @return ServiceRegistry
|
|
*/
|
|
public static ServiceRegistry getServiceRegistry(ServletContext sc)
|
|
{
|
|
WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
|
|
return (ServiceRegistry)wc.getBean(ServiceRegistry.SERVICE_REGISTRY);
|
|
}
|
|
|
|
/**
|
|
* Perform an authentication for the servlet request URI. Processing any "ticket" or
|
|
* "guest" URL arguments.
|
|
*
|
|
* @return AuthenticationStatus
|
|
*
|
|
* @throws IOException
|
|
*/
|
|
public AuthenticationStatus servletAuthenticate(HttpServletRequest req, HttpServletResponse res)
|
|
throws IOException
|
|
{
|
|
return servletAuthenticate(req, res, true);
|
|
}
|
|
|
|
/**
|
|
* Perform an authentication for the servlet request URI. Processing any "ticket" or
|
|
* "guest" URL arguments.
|
|
*
|
|
* @return AuthenticationStatus
|
|
*
|
|
* @throws IOException
|
|
*/
|
|
public AuthenticationStatus servletAuthenticate(HttpServletRequest req, HttpServletResponse res,
|
|
boolean redirectToLoginPage) throws IOException
|
|
{
|
|
AuthenticationStatus status;
|
|
|
|
// see if a ticket or a force Guest parameter has been supplied
|
|
String ticket = req.getParameter(ARG_TICKET);
|
|
if (ticket != null && ticket.length() != 0)
|
|
{
|
|
status = AuthenticationHelper.authenticate(getServletContext(), req, res, ticket);
|
|
}
|
|
else
|
|
{
|
|
boolean forceGuest = false;
|
|
String guest = req.getParameter(ARG_GUEST);
|
|
if (guest != null)
|
|
{
|
|
forceGuest = Boolean.parseBoolean(guest);
|
|
}
|
|
status = AuthenticationHelper.authenticate(getServletContext(), req, res, forceGuest);
|
|
}
|
|
if (status == AuthenticationStatus.Failure && redirectToLoginPage)
|
|
{
|
|
// authentication failed - now need to display the login page to the user, if asked to
|
|
redirectToLoginPage(req, res, getServletContext());
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* Check the user has the given permission on the given node. If they do not either force a log on if this is a guest
|
|
* user or forward to an error page.
|
|
*
|
|
* @param req
|
|
* the request
|
|
* @param res
|
|
* the response
|
|
* @param nodeRef
|
|
* the node in question
|
|
* @param allowLogIn
|
|
* Indicates whether guest users without access to the node should be redirected to the log in page. If
|
|
* <code>false</code>, a status 403 forbidden page is displayed instead.
|
|
* @return <code>true</code>, if the user has access
|
|
* @throws IOException
|
|
* Signals that an I/O exception has occurred.
|
|
* @throws ServletException
|
|
* On other errors
|
|
*/
|
|
public boolean checkAccess(HttpServletRequest req, HttpServletResponse res, NodeRef nodeRef, String permission,
|
|
boolean allowLogIn) throws IOException, ServletException
|
|
{
|
|
ServletContext sc = getServletContext();
|
|
ServiceRegistry serviceRegistry = getServiceRegistry(sc);
|
|
PermissionService permissionService = serviceRegistry.getPermissionService();
|
|
|
|
// check that the user has the permission
|
|
if (permissionService.hasPermission(nodeRef, permission) == AccessStatus.DENIED)
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("User does not have " + permission + " permission for NodeRef: " + nodeRef.toString());
|
|
|
|
if (allowLogIn && serviceRegistry.getAuthorityService().hasGuestAuthority())
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("Redirecting to login page...");
|
|
redirectToLoginPage(req, res, sc);
|
|
}
|
|
else
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("Forwarding to error page...");
|
|
Application
|
|
.handleSystemError(sc, req, res, MSG_ERROR_PERMISSIONS, HttpServletResponse.SC_FORBIDDEN, logger);
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Redirect to the Login page - saving the current URL which can be redirected back later
|
|
* once the user has successfully completed the authentication process.
|
|
*/
|
|
public static void redirectToLoginPage(HttpServletRequest req, HttpServletResponse res, ServletContext sc)
|
|
throws IOException
|
|
{
|
|
redirectToLoginPage(req, res, sc, AuthenticationHelper.getRemoteUserMapper(sc) == null);
|
|
}
|
|
|
|
/**
|
|
* Redirect to the Login page - saving the current URL which can be redirected back later
|
|
* once the user has successfully completed the authentication process.
|
|
* @param sendRedirect allow a redirect status code to be set? If <code>false</code> redirect
|
|
* will be via markup rather than status code (to allow the status code to be used for handshake
|
|
* responses etc.
|
|
*/
|
|
public static void redirectToLoginPage(HttpServletRequest req, HttpServletResponse res, ServletContext sc, boolean sendRedirect)
|
|
throws IOException
|
|
{
|
|
// authentication failed - so end servlet execution and redirect to login page
|
|
StringBuilder redirectURL = new StringBuilder(1024).append(req.getContextPath()).append(FACES_SERVLET).append(
|
|
Application.getLoginPage(sc));
|
|
|
|
// Pass the full requested URL as a parameter so the login page knows where to redirect to later
|
|
String uri = req.getRequestURI();
|
|
|
|
// if we find a JSF servlet reference in the URI then we need to check if the rest of the
|
|
// JSP specified is valid for a redirect operation after Login has occured.
|
|
int jspIndex;
|
|
if (uri.indexOf(req.getContextPath() + FACES_SERVLET) == -1
|
|
|| uri.length() > (jspIndex = uri.indexOf(BaseServlet.FACES_SERVLET) + BaseServlet.FACES_SERVLET.length())
|
|
&& BaseServlet.validRedirectJSP(uri.substring(jspIndex)))
|
|
{
|
|
if (redirectURL.indexOf("?") == -1)
|
|
{
|
|
redirectURL.append('?');
|
|
}
|
|
else
|
|
{
|
|
redirectURL.append('&');
|
|
}
|
|
redirectURL.append(LoginOutcomeBean.PARAM_REDIRECT_URL);
|
|
redirectURL.append('=');
|
|
String url = uri;
|
|
|
|
// Append the query string if necessary
|
|
String queryString = req.getQueryString();
|
|
if (queryString != null)
|
|
{
|
|
// Strip out leading ticket arguments
|
|
queryString = queryString.replaceAll("(?<=^|&)" + ARG_TICKET + "(=[^&=]*)?&", "");
|
|
// Strip out trailing ticket arguments
|
|
queryString = queryString.replaceAll("(^|&)" + ARG_TICKET + "(=[^&=]*)?(?=&|$)", "");
|
|
if (queryString.length() != 0)
|
|
{
|
|
url += "?" + queryString;
|
|
}
|
|
}
|
|
redirectURL.append(URLEncoder.encode(url, "UTF-8"));
|
|
}
|
|
|
|
// If external authentication isn't in use (e.g. proxied share authentication), it's safe to return a redirect to the client
|
|
if (sendRedirect)
|
|
{
|
|
res.sendRedirect(redirectURL.toString());
|
|
}
|
|
// Otherwise, we must signal to the client with an unauthorized status code and rely on a browser refresh to do
|
|
// the redirect for failover login (as we do with NTLM, Kerberos)
|
|
else
|
|
{
|
|
res.setContentType("text/html; charset=UTF-8");
|
|
res.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
|
|
|
final PrintWriter out = res.getWriter();
|
|
out.println("<html><head>");
|
|
out.println("<meta http-equiv=\"Refresh\" content=\"0; url=" + redirectURL + "\">");
|
|
out.println("</head><body><p>Please <a href=\"" + redirectURL + "\">log in</a>.</p>");
|
|
out.println("</body></html>");
|
|
out.close();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Apply the headers required to disallow caching of the response in the browser
|
|
*/
|
|
public static void setNoCacheHeaders(HttpServletResponse res)
|
|
{
|
|
res.setHeader("Cache-Control", "no-cache");
|
|
res.setHeader("Pragma", "no-cache");
|
|
}
|
|
|
|
/**
|
|
* Returns true if the specified JSP file is valid for a redirect after login.
|
|
* Only a specific sub-set of the available JSPs are valid to jump directly too after a
|
|
* clean login attempt - e.g. those that do not require JSF bean context setup. This is
|
|
* a limitation of the JSP architecture. The ExternalAccessServlet provides a mechanism to
|
|
* setup the JSF bean context directly for some specific cases.
|
|
*
|
|
* @param jsp Filename of JSP to check, for example "/jsp/browse/browse.jsp"
|
|
*
|
|
* @return true if the JSP is in the list of valid direct URLs, false otherwise
|
|
*/
|
|
public static boolean validRedirectJSP(String jsp)
|
|
{
|
|
return validRedirectJSPs.contains(jsp);
|
|
}
|
|
|
|
/**
|
|
* Resolves the given path elements to a NodeRef in the current repository
|
|
*
|
|
* @param context Faces context
|
|
* @param args The elements of the path to lookup
|
|
*/
|
|
public static NodeRef resolveWebDAVPath(FacesContext context, String[] args)
|
|
{
|
|
WebApplicationContext wc = FacesContextUtils.getRequiredWebApplicationContext(context);
|
|
return resolveWebDAVPath(wc, args, true);
|
|
}
|
|
|
|
/**
|
|
* Resolves the given path elements to a NodeRef in the current repository
|
|
*
|
|
* @param context Faces context
|
|
* @param args The elements of the path to lookup
|
|
* @param decode True to decode the arg from UTF-8 format, false for no decoding
|
|
*/
|
|
public static NodeRef resolveWebDAVPath(FacesContext context, String[] args, boolean decode)
|
|
{
|
|
WebApplicationContext wc = FacesContextUtils.getRequiredWebApplicationContext(context);
|
|
return resolveWebDAVPath(wc, args, decode);
|
|
}
|
|
|
|
/**
|
|
* Resolves the given path elements to a NodeRef in the current repository
|
|
*
|
|
* @param context ServletContext context
|
|
* @param args The elements of the path to lookup
|
|
*/
|
|
public static NodeRef resolveWebDAVPath(ServletContext context, String[] args)
|
|
{
|
|
WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
|
|
return resolveWebDAVPath(wc, args, true);
|
|
}
|
|
|
|
/**
|
|
* Resolves the given path elements to a NodeRef in the current repository
|
|
*
|
|
* @param context ServletContext context
|
|
* @param args The elements of the path to lookup
|
|
* @param decode True to decode the arg from UTF-8 format, false for no decoding
|
|
*/
|
|
public static NodeRef resolveWebDAVPath(ServletContext context, String[] args, boolean decode)
|
|
{
|
|
WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
|
|
return resolveWebDAVPath(wc, args, decode);
|
|
}
|
|
|
|
/**
|
|
* Resolves the given path elements to a NodeRef in the current repository
|
|
*
|
|
* @param WebApplicationContext Context
|
|
* @param args The elements of the path to lookup
|
|
* @param decode True to decode the arg from UTF-8 format, false for no decoding
|
|
*/
|
|
private static NodeRef resolveWebDAVPath(final WebApplicationContext wc, final String[] args, final boolean decode)
|
|
{
|
|
return AuthenticationUtil.runAs(new RunAsWork<NodeRef>()
|
|
{
|
|
public NodeRef doWork() throws Exception
|
|
{
|
|
NodeRef nodeRef = null;
|
|
|
|
List<String> paths = new ArrayList<String>(args.length - 1);
|
|
|
|
FileInfo file = null;
|
|
try
|
|
{
|
|
// create a list of path elements (decode the URL as we go)
|
|
for (int x = 1; x < args.length; x++)
|
|
{
|
|
paths.add(decode ? URLDecoder.decode(args[x]) : args[x]);
|
|
}
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("Attempting to resolve webdav path: " + paths);
|
|
|
|
// get the company home node to start the search from
|
|
nodeRef = new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId());
|
|
|
|
TenantService tenantService = (TenantService)wc.getBean("tenantService");
|
|
if (tenantService != null && tenantService.isEnabled())
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("MT is enabled.");
|
|
|
|
NodeService nodeService = (NodeService) wc.getBean("NodeService");
|
|
SearchService searchService = (SearchService) wc.getBean("SearchService");
|
|
NamespaceService namespaceService = (NamespaceService) wc.getBean("NamespaceService");
|
|
|
|
// TODO: since these constants are used more widely than just the WebDAVServlet,
|
|
// they should be defined somewhere other than in that servlet
|
|
String rootPath = wc.getServletContext().getInitParameter(BaseServlet.KEY_ROOT_PATH);
|
|
|
|
// note: rootNodeRef is required (for storeRef part)
|
|
nodeRef = tenantService.getRootNode(nodeService, searchService, namespaceService, rootPath, nodeRef);
|
|
}
|
|
|
|
if (paths.size() != 0)
|
|
{
|
|
FileFolderService ffs = (FileFolderService)wc.getBean("FileFolderService");
|
|
file = ffs.resolveNamePath(nodeRef, paths);
|
|
nodeRef = file.getNodeRef();
|
|
}
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("Resolved webdav path to NodeRef: " + nodeRef);
|
|
}
|
|
catch (FileNotFoundException fne)
|
|
{
|
|
if (logger.isWarnEnabled())
|
|
logger.warn("Failed to resolve webdav path", fne);
|
|
|
|
nodeRef = null;
|
|
}
|
|
return nodeRef;
|
|
}
|
|
}, AuthenticationUtil.getSystemUserName());
|
|
}
|
|
|
|
/**
|
|
* Resolve a name based into a NodeRef and Filename string
|
|
*
|
|
* @param sc ServletContext
|
|
* @param path 'cm:name' based path using the '/' character as a separator
|
|
*
|
|
* @return PathRefInfo structure containing the resolved NodeRef and filename
|
|
*
|
|
* @throws IllegalArgumentException
|
|
*/
|
|
public final static PathRefInfo resolveNamePath(ServletContext sc, String path)
|
|
{
|
|
StringTokenizer t = new StringTokenizer(path, "/");
|
|
int tokenCount = t.countTokens();
|
|
String[] elements = new String[tokenCount];
|
|
for (int i=0; i<tokenCount; i++)
|
|
{
|
|
elements[i] = t.nextToken();
|
|
}
|
|
|
|
// process name based path tokens using the webdav path resolving helper
|
|
NodeRef nodeRef = resolveWebDAVPath(sc, elements, false);
|
|
if (nodeRef == null)
|
|
{
|
|
// unable to resolve path - output helpful error to the user
|
|
throw new IllegalArgumentException("Unable to resolve item Path: " + path);
|
|
}
|
|
|
|
return new PathRefInfo(nodeRef, elements[tokenCount - 1]);
|
|
}
|
|
|
|
/**
|
|
* Simple structure class for returning both a NodeRef and Filename String
|
|
* @author Kevin Roast
|
|
*/
|
|
public static class PathRefInfo
|
|
{
|
|
PathRefInfo(NodeRef ref, String filename)
|
|
{
|
|
this.NodeRef = ref;
|
|
this.Filename = filename;
|
|
}
|
|
public NodeRef NodeRef;
|
|
public String Filename;
|
|
}
|
|
}
|