diff --git a/config/alfresco/messages/webclient.properties b/config/alfresco/messages/webclient.properties index 20f8c871d6..47c1246beb 100644 --- a/config/alfresco/messages/webclient.properties +++ b/config/alfresco/messages/webclient.properties @@ -832,6 +832,7 @@ group_search_info=To find a group search for it using group name. Alternatively user_change_homespace_info=Selecting a new home space for a user will not remove the existing permissions on the original home space. You may wish to use the Manage Space Users dialog to modify permissions if they are no longer required on the original home space. quota_totalusage=Total Usage (for this search) quota_totalquota=Total Quota (for this search) +caused_by=caused by: # Content Wizard messages add_content_dialog_title=Add Content Dialog @@ -1975,6 +1976,10 @@ error_search_not_exist=Search does not exist with name: {0} error_search_not_exist=Search does not exist with name: \"{0}\" error_retrieving_search_results=Error getting results for search \"{0}\" - \"{1}\" error_domain_mismatch=Domain mismatch: expected = {0}, actual = {1} +error_not_stored=No error currently stored +error_no_stack_trace=No stack trace available +error_permissions=You do not have sufficient permissions to view the requested item. +error_not_found=Sorry, the requested file does not exist at this location # Confirmations return_to_application=Return to application diff --git a/config/alfresco/web-client-config-actions.xml b/config/alfresco/web-client-config-actions.xml index 7e217b4fe2..980579557f 100644 --- a/config/alfresco/web-client-config-actions.xml +++ b/config/alfresco/web-client-config-actions.xml @@ -722,7 +722,7 @@ - Write + CreateChildren import /images/icons/import.gif diff --git a/source/java/org/alfresco/web/action/evaluator/UnlockDocEvaluator.java b/source/java/org/alfresco/web/action/evaluator/UnlockDocEvaluator.java index 8c1a7d44e6..0e97cc1af6 100644 --- a/source/java/org/alfresco/web/action/evaluator/UnlockDocEvaluator.java +++ b/source/java/org/alfresco/web/action/evaluator/UnlockDocEvaluator.java @@ -18,6 +18,10 @@ */ package org.alfresco.web.action.evaluator; +import javax.faces.context.FacesContext; + +import org.alfresco.service.cmr.coci.CheckOutCheckInService; +import org.alfresco.web.app.servlet.FacesHelper; import org.alfresco.web.bean.repository.Node; /** @@ -34,6 +38,16 @@ public class UnlockDocEvaluator extends BaseActionEvaluator */ public boolean evaluate(Node node) { - return (node.isLocked() == true); + if (node.isLocked()) + { + FacesContext fc = FacesContext.getCurrentInstance(); + CheckOutCheckInService checkOutCheckInService = (CheckOutCheckInService) FacesHelper.getManagedBean(fc, "CheckoutCheckinService"); + if (checkOutCheckInService.getWorkingCopy(node.getNodeRef()) == null) + { + return true; + } + } + + return false; } } diff --git a/source/java/org/alfresco/web/app/Application.java b/source/java/org/alfresco/web/app/Application.java index bbff14743e..d9860c0fbe 100644 --- a/source/java/org/alfresco/web/app/Application.java +++ b/source/java/org/alfresco/web/app/Application.java @@ -34,6 +34,7 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.alfresco.repo.SessionUser; +import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.importer.ImporterBootstrap; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.security.AuthenticationService; @@ -194,6 +195,78 @@ public class Application } } + /** + * Handles error conditions detected by servlets. + * + * @param servletContext + * The servlet context + * @param request + * The HTTP request + * @param response + * The HTTP response + * @param messageKey + * the resource bundle key for the error mesage + * @param statusCode + * the status code to set on the response + * @param logger + * The logger + * @throws IOException + * Signals that an I/O exception has occurred. + * @throws ServletException + * the servlet exception + */ + public static void handleSystemError(ServletContext servletContext, HttpServletRequest request, + HttpServletResponse response, String messageKey, int statusCode, Log logger) + throws IOException, ServletException + { + // get the error bean from the session and set the error that occurred. + HttpSession session = request.getSession(); + ErrorBean errorBean = (ErrorBean)session.getAttribute(ErrorBean.ERROR_BEAN_NAME); + if (errorBean == null) + { + errorBean = new ErrorBean(); + session.setAttribute(ErrorBean.ERROR_BEAN_NAME, errorBean); + } + errorBean.setErrorMessageKey(messageKey); + errorBean.setReturnPage(null); + + // try and find the configured error page + boolean errorShown = false; + String errorPage = getErrorPage(servletContext); + + if (errorPage != null) + { + if (logger.isDebugEnabled()) + logger.debug("An error has occurred, forwarding to error page: " + errorPage); + + if (!response.isCommitted()) + { + errorShown = true; + response.reset(); + response.setStatus(statusCode); + response.setContentType(MimetypeMap.MIMETYPE_HTML); + response.setCharacterEncoding("utf-8"); + servletContext.getRequestDispatcher(errorPage).include(request, response); + } + else + { + if (logger.isDebugEnabled()) + logger.debug("Response is already committed, re-throwing error"); + } + } + else + { + if (logger.isDebugEnabled()) + logger.debug("No error page defined, re-throwing error"); + } + + // if we could not show the error page for whatever reason, re-throw the error + if (!errorShown) + { + throw new ServletException(getMessage(session, messageKey)); + } + } + /** * Retrieves the DialogManager managed bean * diff --git a/source/java/org/alfresco/web/app/servlet/AuthenticationFilter.java b/source/java/org/alfresco/web/app/servlet/AuthenticationFilter.java index f0502799b5..4bc60b1d29 100644 --- a/source/java/org/alfresco/web/app/servlet/AuthenticationFilter.java +++ b/source/java/org/alfresco/web/app/servlet/AuthenticationFilter.java @@ -112,8 +112,6 @@ public class AuthenticationFilter extends AbstractLifecycleBean implements Depen } else { - BaseServlet.setLanguageFromRequestHeader(httpReq, context); - // continue filter chaining chain.doFilter(req, res); } diff --git a/source/java/org/alfresco/web/app/servlet/AuthenticationHelper.java b/source/java/org/alfresco/web/app/servlet/AuthenticationHelper.java index bc325f2f64..92ca09f2f1 100644 --- a/source/java/org/alfresco/web/app/servlet/AuthenticationHelper.java +++ b/source/java/org/alfresco/web/app/servlet/AuthenticationHelper.java @@ -114,11 +114,6 @@ public final class AuthenticationHelper { I18NUtil.setLocale(Application.getLanguage(req.getSession())); } - else - { - // Set the current thread locale (also for JSF context) - fc.getViewRoot().setLocale(BaseServlet.setLanguageFromRequestHeader(req, sc)); - } // Programatically retrieve the UserPreferencesBean from JSF UserPreferencesBean userPreferencesBean = (UserPreferencesBean) fc.getApplication().createValueBinding( diff --git a/source/java/org/alfresco/web/app/servlet/BaseDownloadContentServlet.java b/source/java/org/alfresco/web/app/servlet/BaseDownloadContentServlet.java index 19df4727c5..eac660bc75 100644 --- a/source/java/org/alfresco/web/app/servlet/BaseDownloadContentServlet.java +++ b/source/java/org/alfresco/web/app/servlet/BaseDownloadContentServlet.java @@ -36,7 +36,6 @@ import javax.servlet.http.HttpServletResponse; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.repo.content.filestore.FileContentReader; -import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileNotFoundException; @@ -47,11 +46,9 @@ import org.alfresco.service.cmr.repository.MimetypeService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.QName; import org.alfresco.web.app.Application; -import org.alfresco.web.bean.LoginBean; import org.apache.commons.logging.Log; import org.springframework.extensions.surf.util.URLDecoder; import org.springframework.extensions.surf.util.URLEncoder; @@ -97,6 +94,7 @@ public abstract class BaseDownloadContentServlet extends BaseServlet protected static final String MIMETYPE_OCTET_STREAM = "application/octet-stream"; protected static final String MSG_ERROR_CONTENT_MISSING = "error_content_missing"; + protected static final String MSG_ERROR_NOT_FOUND = "error_not_found"; protected static final String URL_DIRECT = "d"; protected static final String URL_DIRECT_LONG = "direct"; @@ -114,19 +112,21 @@ public abstract class BaseDownloadContentServlet extends BaseServlet * @return The logger */ protected abstract Log getLogger(); - + /** - * Processes the download request using the current context i.e. no - * authentication checks are made, it is presumed they have already - * been done. + * Processes the download request using the current context i.e. no authentication checks are made, it is presumed + * they have already been done. * - * @param req The HTTP request - * @param res The HTTP response - * @param redirectToLogin Flag to determine whether to redirect to the login - * page if the user does not have the correct permissions + * @param req + * The HTTP request + * @param res + * The HTTP response + * @param allowLogIn + * Indicates whether guest users without access to the content should be redirected to the log in page. If + * false, a status 403 forbidden page is displayed instead. */ protected void processDownloadRequest(HttpServletRequest req, HttpServletResponse res, - boolean redirectToLogin, boolean transmitContent) + boolean allowLogIn, boolean transmitContent) throws ServletException, IOException { Log logger = getLogger(); @@ -160,10 +160,18 @@ public abstract class BaseDownloadContentServlet extends BaseServlet if (path != null && path.length() != 0) { // process the name based path to resolve the NodeRef and the Filename element - PathRefInfo pathInfo = resolveNamePath(getServletContext(), path); - - nodeRef = pathInfo.NodeRef; - filename = pathInfo.Filename; + try + { + PathRefInfo pathInfo = resolveNamePath(getServletContext(), path); + nodeRef = pathInfo.NodeRef; + filename = pathInfo.Filename; + } + catch (IllegalArgumentException e) + { + Application.handleSystemError(getServletContext(), req, res, MSG_ERROR_NOT_FOUND, + HttpServletResponse.SC_NOT_FOUND, logger); + return; + } } else { @@ -200,7 +208,9 @@ public abstract class BaseDownloadContentServlet extends BaseServlet } catch (FileNotFoundException e) { - throw new AlfrescoRuntimeException("Unable to find node reference by relative path:" + uri); + Application.handleSystemError(getServletContext(), req, res, MSG_ERROR_NOT_FOUND, + HttpServletResponse.SC_NOT_FOUND, logger); + return; } } else @@ -229,35 +239,20 @@ public abstract class BaseDownloadContentServlet extends BaseServlet // get the services we need to retrieve the content NodeService nodeService = serviceRegistry.getNodeService(); ContentService contentService = serviceRegistry.getContentService(); - PermissionService permissionService = serviceRegistry.getPermissionService(); + // Check that the node still exists + if (!nodeService.exists(nodeRef)) + { + Application.handleSystemError(getServletContext(), req, res, MSG_ERROR_NOT_FOUND, + HttpServletResponse.SC_NOT_FOUND, logger); + return; + } + try { - // check that the user has at least READ_CONTENT access - else redirect to the login page - if (permissionService.hasPermission(nodeRef, PermissionService.READ_CONTENT) == AccessStatus.DENIED) + // check that the user has at least READ_CONTENT access - else redirect to an error or login page + if (!checkAccess(req, res, nodeRef, PermissionService.READ_CONTENT, allowLogIn)) { - if (logger.isDebugEnabled()) - logger.debug("User does not have permissions to read content for NodeRef: " + nodeRef.toString()); - - if (redirectToLogin) - { - if (logger.isDebugEnabled()) - logger.debug("Redirecting to login page..."); - - // TODO: replace with serviceRegistry.getAuthorityService().hasGuestAuthority() from 3.1E - if (!AuthenticationUtil.getFullyAuthenticatedUser().equals(AuthenticationUtil.getGuestUserName())) - { - req.getSession().setAttribute(LoginBean.LOGIN_NOPERMISSIONS, Boolean.TRUE); - } - redirectToLoginPage(req, res, getServletContext()); - } - else - { - if (logger.isDebugEnabled()) - logger.debug("Returning 403 Forbidden error..."); - - res.sendError(HttpServletResponse.SC_FORBIDDEN); - } return; } @@ -512,7 +507,6 @@ public abstract class BaseDownloadContentServlet extends BaseServlet throws IOException { final Log logger = getLogger(); - final boolean trace = logger.isTraceEnabled(); // return the sets of bytes as requested in the content-range header // the response will be formatted as multipart/byteranges media type message diff --git a/source/java/org/alfresco/web/app/servlet/BaseServlet.java b/source/java/org/alfresco/web/app/servlet/BaseServlet.java index 541e4c4a15..3718e5ffb6 100644 --- a/source/java/org/alfresco/web/app/servlet/BaseServlet.java +++ b/source/java/org/alfresco/web/app/servlet/BaseServlet.java @@ -23,17 +23,16 @@ import java.net.URLEncoder; import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.Locale; 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.springframework.extensions.surf.util.I18NUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.tenant.TenantService; @@ -44,14 +43,15 @@ 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.springframework.extensions.surf.util.URLDecoder; import org.alfresco.web.app.Application; -import org.alfresco.web.bean.LoginBean; 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; @@ -72,6 +72,8 @@ public abstract class BaseServlet extends HttpServlet /** 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 validRedirectJSPs = new HashSet(); @@ -160,6 +162,56 @@ public abstract class BaseServlet extends HttpServlet 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 + * false, a status 403 forbidden page is displayed instead. + * @return true, 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. @@ -192,45 +244,25 @@ public abstract class BaseServlet extends HttpServlet redirectURL.append(LoginOutcomeBean.PARAM_REDIRECT_URL); redirectURL.append('='); String url = uri; - if (req.getQueryString() != null && req.getQueryString().length() != 0) + + // Append the query string if necessary + String queryString = req.getQueryString(); + if (queryString != null) { - url += "?" + req.getQueryString(); + // 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")); } res.sendRedirect(redirectURL.toString()); } - /** - * Apply Client and Repository language locale based on the 'Accept-Language' request header - */ - public static Locale setLanguageFromRequestHeader(HttpServletRequest req, ServletContext sc) - { - Locale locale = null; - - // Set the current locale and language - if (Application.getClientConfig(sc).isLanguageSelect()) - { - locale = Application.getLanguage(req.getSession()); - } - else - { - // set language locale from browser header - String acceptLang = req.getHeader("Accept-Language"); - if (acceptLang != null && acceptLang.length() != 0) - { - StringTokenizer t = new StringTokenizer(acceptLang, ",; "); - // get language and convert to java locale format - String language = t.nextToken().replace('-', '_'); - Application.setLanguage(req.getSession(), language); - locale = I18NUtil.parseLocale(language); - I18NUtil.setLocale(locale); - } - } - - return locale; - } - /** * Apply the headers required to disallow caching of the response in the browser */ diff --git a/source/java/org/alfresco/web/app/servlet/ExternalAccessServlet.java b/source/java/org/alfresco/web/app/servlet/ExternalAccessServlet.java index 4357961795..8611ee802f 100644 --- a/source/java/org/alfresco/web/app/servlet/ExternalAccessServlet.java +++ b/source/java/org/alfresco/web/app/servlet/ExternalAccessServlet.java @@ -155,12 +155,9 @@ public class ExternalAccessServlet extends BaseServlet if (nodeRef != null) { - // check that the user has at least READ access - else redirect to the login page - if (permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.DENIED) + // check that the user has at least READ access - else redirect to an error or login page + if (!checkAccess(req, res, nodeRef, PermissionService.READ_CONTENT, true)) { - if (logger.isDebugEnabled()) - logger.debug("User does not have permissions to READ NodeRef: " + nodeRef.toString()); - redirectToLoginPage(req, res, getServletContext()); return; } @@ -189,12 +186,9 @@ public class ExternalAccessServlet extends BaseServlet if (nodeRef != null) { - // check that the user has at least READ access - else redirect to the login page - if (permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.DENIED) + // check that the user has at least READ access - else redirect to an error or login page + if (!checkAccess(req, res, nodeRef, PermissionService.READ_CONTENT, true)) { - if (logger.isDebugEnabled()) - logger.debug("User does not have permissions to READ NodeRef: " + nodeRef.toString()); - redirectToLoginPage(req, res, getServletContext()); return; } @@ -225,12 +219,9 @@ public class ExternalAccessServlet extends BaseServlet if (nodeRef != null) { - // check that the user has at least READ access - else redirect to the login page - if (permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.DENIED) + // check that the user has at least READ access - else redirect to an error or login page + if (!checkAccess(req, res, nodeRef, PermissionService.READ_CONTENT, true)) { - if (logger.isDebugEnabled()) - logger.debug("User does not have permissions to READ NodeRef: " + nodeRef.toString()); - redirectToLoginPage(req, res, getServletContext()); return; } diff --git a/source/java/org/alfresco/web/app/servlet/FacesHelper.java b/source/java/org/alfresco/web/app/servlet/FacesHelper.java index 5de4bce98a..b2dbfffb82 100644 --- a/source/java/org/alfresco/web/app/servlet/FacesHelper.java +++ b/source/java/org/alfresco/web/app/servlet/FacesHelper.java @@ -166,7 +166,7 @@ public final class FacesHelper // catch exception to resolve ADB-158/ACT-7343 // not much we can do here, just make sure return is null if (logger.isDebugEnabled()) - logger.debug("Failed to resolve managed bean: " + name); + logger.debug("Failed to resolve managed bean: " + name, ee); obj = null; } diff --git a/source/java/org/alfresco/web/app/servlet/GlobalLocalizationFilter.java b/source/java/org/alfresco/web/app/servlet/GlobalLocalizationFilter.java new file mode 100644 index 0000000000..5a9f418d69 --- /dev/null +++ b/source/java/org/alfresco/web/app/servlet/GlobalLocalizationFilter.java @@ -0,0 +1,95 @@ +/* + * 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 . + */ +package org.alfresco.web.app.servlet; + +import java.io.IOException; +import java.util.Locale; +import java.util.StringTokenizer; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; + +import org.springframework.extensions.surf.util.I18NUtil; + +/** + * @author Stas Sokolovsky + * + * Servlet filter responsible for setting a fallback default locale for ALL requests. + */ +public class GlobalLocalizationFilter implements Filter +{ + /** + * Run the filter + * + * @param request ServletRequest + * @param response ServletResponse + * @param chain FilterChain + * @exception IOException + * @exception ServletException + */ + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException + { + HttpServletRequest httpRequest = (HttpServletRequest) request; + + setLanguageFromRequestHeader(httpRequest); + + // continue filter chaining + chain.doFilter(request, response); + + } + + /** + * Apply Client and Repository language locale based on the 'Accept-Language' request header + * + * @param request HttpServletRequest + */ + public void setLanguageFromRequestHeader(HttpServletRequest req) + { + Locale locale = null; + + String acceptLang = req.getHeader("Accept-Language"); + if (acceptLang != null && acceptLang.length() > 0) + { + StringTokenizer tokenizer = new StringTokenizer(acceptLang, ",; "); + // get language and convert to java locale format + String language = tokenizer.nextToken().replace('-', '_'); + locale = I18NUtil.parseLocale(language); + I18NUtil.setLocale(locale); + } + else + { + I18NUtil.setLocale(Locale.getDefault()); + } + } + + public void init(FilterConfig filterConfig) throws ServletException + { + // Nothing to do + } + + public void destroy() + { + // Nothing to do + } +} diff --git a/source/java/org/alfresco/web/bean/ErrorBean.java b/source/java/org/alfresco/web/bean/ErrorBean.java index 9945c91b85..7b361f9dd8 100644 --- a/source/java/org/alfresco/web/bean/ErrorBean.java +++ b/source/java/org/alfresco/web/bean/ErrorBean.java @@ -18,9 +18,7 @@ */ package org.alfresco.web.bean; -import java.io.PrintWriter; import java.io.Serializable; -import java.io.StringWriter; import javax.servlet.ServletException; @@ -37,6 +35,7 @@ public class ErrorBean implements Serializable private String returnPage; private Throwable lastError; + private String errorMessageKey; /** * @return Returns the page to go back to after the error has been displayed @@ -79,68 +78,29 @@ public class ErrorBean implements Serializable { this.lastError = error; } + this.errorMessageKey = null; } - + /** - * @return Returns the last error to occur in string form + * Gets the error message key. + * + * @return the error message key */ - public String getLastErrorMessage() + public String getErrorMessageKey() { - String message = "No error currently stored"; - - if (this.lastError != null) - { - StringBuilder builder = new StringBuilder(this.lastError.toString());; - Throwable cause = this.lastError.getCause(); - - // build up stack trace of all causes - while (cause != null) - { - builder.append("\ncaused by:\n"); - builder.append(cause.toString()); - - if (cause instanceof ServletException && - ((ServletException)cause).getRootCause() != null) - { - cause = ((ServletException)cause).getRootCause(); - } - else - { - cause = cause.getCause(); - } - } - - message = builder.toString(); - - // format the message for HTML display - message = message.replaceAll("<", "<"); - message = message.replaceAll(">", ">"); - message = message.replaceAll("\n", "
"); - } - - return message; + return errorMessageKey; } - + /** - * @return Returns the stack trace for the last error + * Sets the error message key. + * + * @param errorMessageKey + * the new error message key */ - public String getStackTrace() + public void setErrorMessageKey(String errorMessageKey) { - String trace = "No stack trace available"; - - if (this.lastError != null) - { - StringWriter stringWriter = new StringWriter(); - PrintWriter writer = new PrintWriter(stringWriter); - this.lastError.printStackTrace(writer); - - // format the message for HTML display - trace = stringWriter.toString(); - trace = trace.replaceAll("<", "<"); - trace = trace.replaceAll(">", ">"); - trace = trace.replaceAll("\n", "
"); - } - - return trace; + this.errorMessageKey = errorMessageKey; + this.lastError = null; } + } diff --git a/source/java/org/alfresco/web/bean/content/InviteContentUsersWizard.java b/source/java/org/alfresco/web/bean/content/InviteContentUsersWizard.java index 81f37eb2a6..b76c498a75 100644 --- a/source/java/org/alfresco/web/bean/content/InviteContentUsersWizard.java +++ b/source/java/org/alfresco/web/bean/content/InviteContentUsersWizard.java @@ -35,18 +35,11 @@ public class InviteContentUsersWizard extends BaseInviteUsersWizard { private static final long serialVersionUID = 9198783146031469545L; - /** Cache of available content permissions */ - Set contentPermissions = null; - @Override protected Set getPermissionsForType() { - if (this.contentPermissions == null) - { - this.contentPermissions = this.getPermissionService().getSettablePermissions(getNode().getType()); - } - - return this.contentPermissions; + // Let the permission service do the caching to allow for dynamic model updates, etc. + return this.permissionService.getSettablePermissions(getNode().getType()); } @Override diff --git a/source/java/org/alfresco/web/bean/users/UserMembersBean.java b/source/java/org/alfresco/web/bean/users/UserMembersBean.java index 6229363f63..7db93d5501 100644 --- a/source/java/org/alfresco/web/bean/users/UserMembersBean.java +++ b/source/java/org/alfresco/web/bean/users/UserMembersBean.java @@ -37,6 +37,7 @@ import javax.faces.model.ListDataModel; import javax.transaction.UserTransaction; import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; @@ -814,16 +815,26 @@ public abstract class UserMembersBean extends BaseDialogBean implements IContext // clear the currently set permissions for this user // and add each of the new permissions in turn - NodeRef nodeRef = getNode().getNodeRef(); - this.getPermissionService().clearPermission(nodeRef, getPersonAuthority()); - for (PermissionWrapper wrapper : personRoles) + final NodeRef nodeRef = getNode().getNodeRef(); + if (this.getPermissionService().hasPermission(nodeRef, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED) { - this.getPermissionService().setPermission( - nodeRef, - getPersonAuthority(), - wrapper.getPermission(), - true); - } + AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() { + public Object doWork() throws Exception + { + getPermissionService().clearPermission(nodeRef, getPersonAuthority()); + for (PermissionWrapper wrapper : personRoles) + { + getPermissionService().setPermission( + nodeRef, + getPersonAuthority(), + wrapper.getPermission(), + true); + } + return null; + } + + }, AuthenticationUtil.getSystemUserName()); + } tx.commit(); } diff --git a/source/java/org/alfresco/web/bean/workflow/StartWorkflowWizard.java b/source/java/org/alfresco/web/bean/workflow/StartWorkflowWizard.java index f436780f04..1c525bea53 100644 --- a/source/java/org/alfresco/web/bean/workflow/StartWorkflowWizard.java +++ b/source/java/org/alfresco/web/bean/workflow/StartWorkflowWizard.java @@ -615,7 +615,7 @@ public class StartWorkflowWizard extends BaseWizardBean sorter.sort(); // select the first workflow in the list - if (this.availableWorkflows.size() > 0) + if (this.availableWorkflows.size() > 0 && previouslySelectedWorkflow == null) { this.selectedWorkflow = (String)this.availableWorkflows.get(0).getValue(); } diff --git a/source/java/org/alfresco/web/forms/FormsService.java b/source/java/org/alfresco/web/forms/FormsService.java index e8cd3ba507..caf16c4614 100644 --- a/source/java/org/alfresco/web/forms/FormsService.java +++ b/source/java/org/alfresco/web/forms/FormsService.java @@ -378,7 +378,11 @@ public final class FormsService LOGGER.debug("removing configuration for " + formName + " from web project " + this.nodeService.getProperty(parentRef, ContentModel.PROP_NAME)); } - this.nodeService.removeChild(parentRef, ref); + // ALF-3751: Validate this is the real form folder rather than a copy + if (childRef.getParentRef().equals(parentRef)) + { + this.nodeService.removeChild(parentRef, ref); + } } } diff --git a/source/java/org/alfresco/web/ui/common/SortableSelectItem.java b/source/java/org/alfresco/web/ui/common/SortableSelectItem.java index 78ef4f13be..2559e1a77d 100644 --- a/source/java/org/alfresco/web/ui/common/SortableSelectItem.java +++ b/source/java/org/alfresco/web/ui/common/SortableSelectItem.java @@ -35,10 +35,23 @@ public final class SortableSelectItem extends SelectItem implements Comparable public int compareTo(Object obj2) { - if (this.sort == null && obj2 == null) return 0; - if (this.sort == null) return -1; - if (obj2 == null) return 1; - return this.sort.compareToIgnoreCase( ((SortableSelectItem)obj2).sort ); + SortableSelectItem s2 = ((SortableSelectItem)obj2); + if (this.sort == null) + { + if (s2 == null || s2.sort == null) + { + return 0; + } + return -1; + } + else + { + if (s2 == null || s2.sort == null) + { + return 1; + } + return this.sort.compareToIgnoreCase( s2.sort ); + } } private String sort; diff --git a/source/java/org/alfresco/web/ui/common/Utils.java b/source/java/org/alfresco/web/ui/common/Utils.java index 64333d22e8..4e24f3724c 100644 --- a/source/java/org/alfresco/web/ui/common/Utils.java +++ b/source/java/org/alfresco/web/ui/common/Utils.java @@ -1059,13 +1059,14 @@ public final class Utils extends StringUtils for (StringTokenizer t = new StringTokenizer(term.trim(), " "); t.hasMoreTokens(); /**/) { String token = LuceneQueryParser.escape(t.nextToken()); - query.append("@").append(NamespaceService.CONTENT_MODEL_PREFIX).append("\\:firstName:\"*"); + query.append("+TYPE:\"").append(ContentModel.TYPE_PERSON).append("\" "); + query.append("+(@").append(NamespaceService.CONTENT_MODEL_PREFIX).append("\\:firstName:\"*"); query.append(token); query.append("*\" @").append(NamespaceService.CONTENT_MODEL_PREFIX).append("\\:lastName:\"*"); query.append(token); query.append("*\" @").append(NamespaceService.CONTENT_MODEL_PREFIX).append("\\:userName:"); query.append(token); - query.append("* "); + query.append("*) "); } } } diff --git a/source/java/org/alfresco/web/ui/repo/component/UIAjaxTagPicker.java b/source/java/org/alfresco/web/ui/repo/component/UIAjaxTagPicker.java index 74bf8b7e23..c725fd721b 100644 --- a/source/java/org/alfresco/web/ui/repo/component/UIAjaxTagPicker.java +++ b/source/java/org/alfresco/web/ui/repo/component/UIAjaxTagPicker.java @@ -218,7 +218,7 @@ public class UIAjaxTagPicker extends BaseAjaxItemPicker out.write(" "); if (selectedNames == null) { - if (getLabel() == "") + if ("".equals(getLabel())) { setLabel(msg.getString(MSG_CLICK_TO_SELECT_TAG)); } diff --git a/source/java/org/alfresco/web/ui/repo/tag/SystemErrorTag.java b/source/java/org/alfresco/web/ui/repo/tag/SystemErrorTag.java index f4ee622ca5..76280e0f33 100644 --- a/source/java/org/alfresco/web/ui/repo/tag/SystemErrorTag.java +++ b/source/java/org/alfresco/web/ui/repo/tag/SystemErrorTag.java @@ -19,10 +19,13 @@ package org.alfresco.web.ui.repo.tag; import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; import java.io.Writer; import java.util.Collections; import java.util.ResourceBundle; +import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.TagSupport; @@ -31,6 +34,7 @@ import org.alfresco.web.app.Application; import org.alfresco.web.app.portlet.AlfrescoFacesPortlet; import org.alfresco.web.app.servlet.ExternalAccessServlet; import org.alfresco.web.bean.ErrorBean; +import org.alfresco.web.ui.common.Utils; /** * A non-JSF tag library that displays the currently stored system error @@ -46,6 +50,9 @@ public class SystemErrorTag extends TagSupport private static final String MSG_HIDE_DETAILS = "hide_details"; private static final String MSG_SHOW_DETAILS = "show_details"; private static final String MSG_LOGOUT = "logout"; + private static final String MSG_ERROR_NOT_STORED = "error_not_stored"; + private static final String MSG_ERROR_NO_STACK_TRACE = "error_no_stack_trace"; + private static final String MSG_CAUSED_BY = "caused_by"; private String styleClass; private String detailsStyleClass; @@ -104,10 +111,7 @@ public class SystemErrorTag extends TagSupport * @see javax.servlet.jsp.tagext.TagSupport#doStartTag() */ public int doStartTag() throws JspException - { - String errorMessage = "No error currently stored"; - String errorDetails = "No details"; - + { // get the error details from the bean, this may be in a portlet // session or a normal servlet session. ErrorBean errorBean = null; @@ -121,12 +125,7 @@ public class SystemErrorTag extends TagSupport getAttribute(ErrorBean.ERROR_BEAN_NAME); } - if (errorBean != null) - { - errorMessage = errorBean.getLastErrorMessage(); - errorDetails = errorBean.getStackTrace(); - } - else + if (errorBean == null) { // if we reach here the error was caught by the declaration in web.xml so // pull all the information from the request and create the error bean @@ -138,9 +137,8 @@ public class SystemErrorTag extends TagSupport pageContext.getSession().setAttribute(ErrorBean.ERROR_BEAN_NAME, errorBean); errorBean.setLastError(error); errorBean.setReturnPage(uri); - errorMessage = errorBean.getLastErrorMessage(); - errorDetails = errorBean.getStackTrace(); } + Throwable lastError = errorBean.getLastError(); try { @@ -148,6 +146,20 @@ public class SystemErrorTag extends TagSupport ResourceBundle bundle = Application.getBundle(pageContext.getSession()); + String errorMessage; + String errorDetails; + if (lastError == null) + { + String messageKey = errorBean.getErrorMessageKey(); + errorMessage = bundle.getString(messageKey == null ? MSG_ERROR_NOT_STORED : messageKey); + errorDetails = bundle.getString(MSG_ERROR_NO_STACK_TRACE); + } + else + { + errorMessage = getLastErrorMessage(lastError, bundle); + errorDetails = getStackTrace(lastError); + } + out.write(""); + return message; + } + + /** + * @return Returns the stack trace for the last error + */ + private String getStackTrace(Throwable lastError) + { + StringWriter stringWriter = new StringWriter(); + PrintWriter writer = new PrintWriter(stringWriter); + lastError.printStackTrace(writer); + + // format the message for HTML display + String trace = Utils.encode(stringWriter.toString()); + trace = trace.replaceAll("\n", "
"); + return trace; + } + } diff --git a/source/test-resources/xforms/examples/getting-started-sample/alfresco-sample-website.war b/source/test-resources/xforms/examples/getting-started-sample/alfresco-sample-website.war index 416c8560cb..4d104b95f1 100644 Binary files a/source/test-resources/xforms/examples/getting-started-sample/alfresco-sample-website.war and b/source/test-resources/xforms/examples/getting-started-sample/alfresco-sample-website.war differ diff --git a/source/web/WEB-INF/web.xml b/source/web/WEB-INF/web.xml index 2a5d0d4d37..25a1228eae 100644 --- a/source/web/WEB-INF/web.xml +++ b/source/web/WEB-INF/web.xml @@ -146,6 +146,17 @@ + + Global Localization Filter + Sets fallback default locale for ALL requests + org.alfresco.web.app.servlet.GlobalLocalizationFilter + + + + Global Localization Filter + /* + + Global Authentication Filter /navigate/* diff --git a/source/web/jsp/content/edit-html-inline.jsp b/source/web/jsp/content/edit-html-inline.jsp index 5f7187f81e..2f48bc511c 100644 --- a/source/web/jsp/content/edit-html-inline.jsp +++ b/source/web/jsp/content/edit-html-inline.jsp @@ -22,6 +22,7 @@ <%@ taglib uri="/WEB-INF/alfresco.tld" prefix="a" %> <%@ taglib uri="/WEB-INF/repo.tld" prefix="r" %> +<%@ page isELIgnored="false" %> <%@ page import="org.alfresco.web.ui.common.PanelGenerator" %> diff --git a/source/web/jsp/content/filelink-details.jsp b/source/web/jsp/content/filelink-details.jsp index 09e93a4911..5286a2cc14 100644 --- a/source/web/jsp/content/filelink-details.jsp +++ b/source/web/jsp/content/filelink-details.jsp @@ -61,7 +61,7 @@ - + @@ -98,8 +98,8 @@ <%-- Document Actions --%> - + - \ No newline at end of file + diff --git a/source/web/jsp/login.jsp b/source/web/jsp/login.jsp index cb9e951370..6dd70c33ca 100644 --- a/source/web/jsp/login.jsp +++ b/source/web/jsp/login.jsp @@ -28,6 +28,7 @@ <%@ page import="org.alfresco.web.ui.common.Utils" %> <%@ page import="org.alfresco.web.app.Application" %> <%@ page import="org.alfresco.web.bean.LoginBean" %> +<%@ page import="org.springframework.extensions.surf.util.I18NUtil" %> <%@ page import="javax.faces.context.FacesContext" %> <%@ page import="javax.servlet.http.Cookie" %> <%@ page import="java.util.Locale" %> @@ -56,9 +57,7 @@ session.setAttribute(AuthenticationHelper.SESSION_USERNAME, authCookieValue); } } - - // setup system locale from the Accept-Language header value - Locale locale = BaseServlet.setLanguageFromRequestHeader(request, application); + %> @@ -69,8 +68,8 @@ <% FacesContext fc = FacesContext.getCurrentInstance(); - // set locale for JSF framework usage - fc.getViewRoot().setLocale(locale); + // set locale for JSF framework usage (passed on by Localization Filter) + fc.getViewRoot().setLocale(I18NUtil.getLocale()); // set permissions error if applicable if (session.getAttribute(LoginBean.LOGIN_NOPERMISSIONS) != null) diff --git a/source/web/jsp/spaces/spacelink-details.jsp b/source/web/jsp/spaces/spacelink-details.jsp index 9eb86d276f..5d478e97c1 100644 --- a/source/web/jsp/spaces/spacelink-details.jsp +++ b/source/web/jsp/spaces/spacelink-details.jsp @@ -56,7 +56,7 @@ - + @@ -97,8 +97,8 @@ <%-- Space Actions --%> - + - \ No newline at end of file +