diff --git a/config/alfresco/messages/office-addin.properties b/config/alfresco/messages/office-addin.properties index d055f3a940..377d734485 100644 --- a/config/alfresco/messages/office-addin.properties +++ b/config/alfresco/messages/office-addin.properties @@ -135,6 +135,7 @@ office.result.exception=Action failed due to exception office.result.create_space.failed=Could not create space office.result.create_space.missing_name=Space must have a Name office.result.space_created=New space created +office.result.user_not_found=User Not Found # Miscellaneous office.unit.kb=KB diff --git a/config/alfresco/messages/office-addin_de_DE.properties b/config/alfresco/messages/office-addin_de_DE.properties index f877402056..c2ba1985c1 100644 --- a/config/alfresco/messages/office-addin_de_DE.properties +++ b/config/alfresco/messages/office-addin_de_DE.properties @@ -134,6 +134,7 @@ office.result.exception=Action failed due to exception office.result.create_space.failed=Could not create space office.result.create_space.missing_name=Space must have a Name office.result.space_created=Ordner angelegt +office.result.user_not_found=User Not Found # Miscellaneous office.unit.kb=KB diff --git a/config/alfresco/web-client-application-context.xml b/config/alfresco/web-client-application-context.xml index fa5317f912..9c9dcad9b2 100644 --- a/config/alfresco/web-client-application-context.xml +++ b/config/alfresco/web-client-application-context.xml @@ -167,11 +167,7 @@ - - - - - + diff --git a/source/java/org/alfresco/repo/web/scripts/portlet/WebClientPortletAuthenticatorFactory.java b/source/java/org/alfresco/repo/web/scripts/portlet/WebClientPortletAuthenticatorFactory.java index 0f0b35ac09..7fa9bdee38 100644 --- a/source/java/org/alfresco/repo/web/scripts/portlet/WebClientPortletAuthenticatorFactory.java +++ b/source/java/org/alfresco/repo/web/scripts/portlet/WebClientPortletAuthenticatorFactory.java @@ -18,66 +18,30 @@ */ package org.alfresco.repo.web.scripts.portlet; +import java.io.IOException; + +import javax.portlet.PortletContext; +import javax.portlet.PortletException; import javax.portlet.PortletSession; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; -import javax.transaction.UserTransaction; -import org.alfresco.repo.SessionUser; -import org.alfresco.repo.model.Repository; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.security.AuthenticationService; -import org.alfresco.service.transaction.TransactionService; -import org.alfresco.web.app.servlet.AuthenticationHelper; -import org.alfresco.web.bean.repository.User; +import org.alfresco.repo.web.scripts.servlet.AuthenticatorServlet; +import org.alfresco.web.app.servlet.AuthenticationStatus; import org.springframework.extensions.webscripts.Authenticator; +import org.springframework.extensions.webscripts.WebScriptException; import org.springframework.extensions.webscripts.Description.RequiredAuthentication; import org.springframework.extensions.webscripts.portlet.PortletAuthenticatorFactory; -import org.springframework.extensions.webscripts.portlet.WebScriptPortletRequest; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; /** * Portlet authenticator which synchronizes with the Alfresco Web Client authentication * * @author davidc + * @author dward */ public class WebClientPortletAuthenticatorFactory implements PortletAuthenticatorFactory { - // Logger - private static final Log logger = LogFactory.getLog(WebClientPortletAuthenticatorFactory.class); - - // dependencies - private AuthenticationService authenticationService; - private TransactionService transactionService; - private Repository repository; - - /** - * @param authenticationService - */ - public void setAuthenticationService(AuthenticationService authenticationService) - { - this.authenticationService = authenticationService; - } - - /** - * @param scriptContext - */ - public void setRepository(Repository repository) - { - this.repository = repository; - } - - /** - * @param transactionService - */ - public void setTransactionService(TransactionService transactionService) - { - this.transactionService = transactionService; - } - /* (non-Javadoc) * @see org.alfresco.web.scripts.portlet.PortletAuthenticatorFactory#create(javax.portlet.RenderRequest, javax.portlet.RenderResponse) */ @@ -112,54 +76,23 @@ public class WebClientPortletAuthenticatorFactory implements PortletAuthenticato public boolean authenticate(RequiredAuthentication required, boolean isGuest) { PortletSession session = req.getPortletSession(); - - // first look for the username key in the session - we add this by hand for some portals - // when the WebScriptPortletRequest is created - String portalUser = (String)req.getPortletSession().getAttribute(WebScriptPortletRequest.ALFPORTLETUSERNAME); - if (portalUser == null) + req.setAttribute(AuthenticatorServlet.ATTR_REQUIRED_AUTH, required); + req.setAttribute(AuthenticatorServlet.ATTR_IS_GUEST, isGuest); + PortletContext context = session.getPortletContext(); + try { - portalUser = req.getRemoteUser(); + context.getNamedDispatcher(AuthenticatorServlet.SERVLET_NAME).include(req, res); } - - if (logger.isDebugEnabled()) - { - logger.debug("JSR-168 Remote user: " + portalUser); - } - - if (isGuest || portalUser == null) + catch (PortletException e) { - if (logger.isDebugEnabled()) - logger.debug("Authenticating as Guest"); - - // authenticate as guest - AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getGuestUserName()); - - if (logger.isDebugEnabled()) - logger.debug("Setting Web Client authentication context for guest"); - - createWebClientUser(session); - removeSessionInvalidated(session); + throw new WebScriptException("Failed to authenticate", e); } - else + catch (IOException e) { - if (logger.isDebugEnabled()) - logger.debug("Authenticating as user " + portalUser); - - AuthenticationUtil.setFullyAuthenticatedUser(portalUser); - - // determine if Web Client context needs to be updated - User user = getWebClientUser(session); - if (user == null || !portalUser.equals(user.getUserName())) - { - if (logger.isDebugEnabled()) - logger.debug("Setting Web Client authentication context for user " + portalUser); - - createWebClientUser(session); - removeSessionInvalidated(session); - } + throw new WebScriptException("Failed to authenticate", e); } - - return true; + AuthenticationStatus status = (AuthenticationStatus) req.getAttribute(AuthenticatorServlet.ATTR_AUTH_STATUS); + return !(status == null || status == AuthenticationStatus.Failure); } /* (non-Javadoc) @@ -167,66 +100,8 @@ public class WebClientPortletAuthenticatorFactory implements PortletAuthenticato */ public boolean emptyCredentials() { - String portalUser = (String)req.getPortletSession().getAttribute(WebScriptPortletRequest.ALFPORTLETUSERNAME); - if (portalUser == null) - { - portalUser = req.getRemoteUser(); - } - return (portalUser == null); - } - - /** - * Helper. Remove Web Client session invalidated flag - * - * @param session - */ - private void removeSessionInvalidated(PortletSession session) - { - session.removeAttribute(AuthenticationHelper.SESSION_INVALIDATED, PortletSession.APPLICATION_SCOPE); - } - - /** - * Helper. Create Web Client session user - * - * @param session - */ - private void createWebClientUser(PortletSession session) - { - UserTransaction tx = null; - try - { - // start a txn as this method interacts with public services - tx = transactionService.getUserTransaction(); - tx.begin(); - - NodeRef personRef = repository.getPerson(); - User user = new User(authenticationService.getCurrentUserName(), authenticationService.getCurrentTicket(), personRef); - NodeRef homeRef = repository.getUserHome(personRef); - if (homeRef != null) - { - user.setHomeSpaceId(homeRef.getId()); - } - session.setAttribute(AuthenticationHelper.AUTHENTICATION_USER, user, PortletSession.APPLICATION_SCOPE); - - tx.commit(); - } - catch (Throwable e) - { - try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} - } - } - - /** - * Helper. Get Web Client session user - * - * @param session - * @return - */ - private User getWebClientUser(PortletSession session) - { - SessionUser user = (SessionUser)session.getAttribute(AuthenticationHelper.AUTHENTICATION_USER, PortletSession.APPLICATION_SCOPE); - return user instanceof User ? (User)user : null; - } + // Ticket - based authentication not supported + return true; + } } - } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/web/scripts/portlet/WebScriptRepoPortlet.java b/source/java/org/alfresco/repo/web/scripts/portlet/WebScriptRepoPortlet.java index d5367ae5ce..2485a98e86 100644 --- a/source/java/org/alfresco/repo/web/scripts/portlet/WebScriptRepoPortlet.java +++ b/source/java/org/alfresco/repo/web/scripts/portlet/WebScriptRepoPortlet.java @@ -48,7 +48,14 @@ public class WebScriptRepoPortlet extends WebScriptPortlet public void processAction(ActionRequest req, ActionResponse res) throws PortletException, PortletSecurityException, IOException { Application.setInPortalServer(true); - super.processAction(req, res); + try + { + super.processAction(req, res); + } + finally + { + Application.setInPortalServer(false); + } } /* (non-Javadoc) @@ -58,7 +65,14 @@ public class WebScriptRepoPortlet extends WebScriptPortlet public void render(RenderRequest req, RenderResponse res) throws PortletException, PortletSecurityException, IOException { Application.setInPortalServer(true); - super.render(req, res); + try + { + super.render(req, res); + } + finally + { + Application.setInPortalServer(false); + } } } diff --git a/source/java/org/alfresco/repo/web/scripts/servlet/AuthenticatorServlet.java b/source/java/org/alfresco/repo/web/scripts/servlet/AuthenticatorServlet.java new file mode 100644 index 0000000000..a4fbcf87e5 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/servlet/AuthenticatorServlet.java @@ -0,0 +1,80 @@ +/* + * 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.repo.web.scripts.servlet; + +import java.io.IOException; + +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.web.app.servlet.AuthenticationHelper; +import org.alfresco.web.app.servlet.AuthenticationStatus; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.webscripts.Description.RequiredAuthentication; + +/** + * This servlet serves as a useful 'subroutine' for portlets, which using their request dispatcher, can go 'through the + * looking glass' to this servlet and use the standard Alfresco servlet api-based authentication mechanisms. + * + * @author dward + */ +public class AuthenticatorServlet extends HttpServlet +{ + public static final String SERVLET_NAME = "authenticatorServlet"; + public static final String ATTR_IS_GUEST = "_alf_isGuest"; + public static final String ATTR_REQUIRED_AUTH = "_alf_requiredAuth"; + public static final String ATTR_AUTH_STATUS = "_alf_authStatus"; + + private static final long serialVersionUID = 5657140557243797744L; + + private static final Log logger = LogFactory.getLog(AuthenticatorServlet.class); + + /* + * (non-Javadoc) + * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) + */ + @Override + protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException + { + ServletContext context = getServletContext(); + boolean isGuest = (Boolean) req.getAttribute(ATTR_IS_GUEST); + RequiredAuthentication required = (RequiredAuthentication) req.getAttribute(ATTR_REQUIRED_AUTH); + AuthenticationStatus status; + if (isGuest && RequiredAuthentication.guest == required) + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating as Guest"); + + status = AuthenticationHelper.authenticate(context, req, res, true); + } + else + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating session"); + + status = AuthenticationHelper.authenticate(context, req, res, false, false); + } + req.setAttribute(ATTR_AUTH_STATUS, status); + } +} diff --git a/source/java/org/alfresco/web/app/Application.java b/source/java/org/alfresco/web/app/Application.java index 85ed0fe6c4..3c37eb8724 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.HttpSession; import org.alfresco.repo.importer.ImporterBootstrap; import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.web.app.portlet.AlfrescoFacesPortlet; import org.alfresco.web.app.servlet.AuthenticationHelper; import org.alfresco.web.app.servlet.FacesHelper; import org.alfresco.web.bean.ErrorBean; @@ -71,7 +72,7 @@ public class Application public static final String MESSAGE_BUNDLE = "alfresco.messages.webclient"; - private static boolean inPortalServer = false; + private static ThreadLocal inPortalServer = new ThreadLocal(); private static StoreRef repoStoreRef; private static String rootPath; private static String companyRootId; @@ -79,8 +80,8 @@ public class Application private static String spaceTemplatesFolderName; private static String contentTemplatesFolderName; private static String emailTemplatesFolderName; - private static String inviteEmailTemplatesFolderName; - private static String notifyEmailTemplatesFolderName; + private static String inviteEmailTemplatesFolderName; + private static String notifyEmailTemplatesFolderName; private static String rssTemplatesFolderName; private static String savedSearchesFolderName; private static String scriptsFolderName; @@ -107,7 +108,7 @@ public class Application */ public static void setInPortalServer(boolean inPortal) { - inPortalServer = inPortal; + inPortalServer.set(inPortal ? Boolean.TRUE : null); } /** @@ -117,7 +118,8 @@ public class Application */ public static boolean inPortalServer() { - return inPortalServer; + Boolean result = inPortalServer.get(); + return result == null ? false : result; } /** @@ -263,7 +265,28 @@ public class Application */ public static User getCurrentUser(FacesContext context) { - return (User)context.getExternalContext().getSessionMap().get(AuthenticationHelper.AUTHENTICATION_USER); + if (inPortalServer()) + { + User user = (User) AlfrescoFacesPortlet.getPortletSessionAttribute(context, + AuthenticationHelper.AUTHENTICATION_USER, true); + if (user != null) + { + return user; + } + } + return (User) context.getExternalContext().getSessionMap().get(AuthenticationHelper.AUTHENTICATION_USER); + } + + public static void setCurrentUser(FacesContext context, User user) + { + if (inPortalServer()) + { + AlfrescoFacesPortlet.setPortletSessionAttribute(context, AuthenticationHelper.AUTHENTICATION_USER, user, true); + } + else + { + context.getExternalContext().getSessionMap().put(AuthenticationHelper.AUTHENTICATION_USER, user); + } } /** diff --git a/source/java/org/alfresco/web/app/ContextListener.java b/source/java/org/alfresco/web/app/ContextListener.java index 39c8956ad8..1cda879b13 100644 --- a/source/java/org/alfresco/web/app/ContextListener.java +++ b/source/java/org/alfresco/web/app/ContextListener.java @@ -157,39 +157,15 @@ public class ContextListener implements ServletContextListener, HttpSessionListe if (logger.isDebugEnabled()) logger.debug("HTTP session destroyed: " + event.getSession().getId()); - String userKey = null; - if (Application.inPortalServer() == false) + SessionUser user = (SessionUser)event.getSession().getAttribute(AuthenticationHelper.AUTHENTICATION_USER); + if (user != null) { - userKey = AuthenticationHelper.AUTHENTICATION_USER; - } - else - { - // search for the user object in the portlet wrapped session keys - // each vendor uses a different naming scheme so we search by hand - String userKeyPostfix = "?" + AuthenticationHelper.AUTHENTICATION_USER; - Enumeration enumNames = event.getSession().getAttributeNames(); - while (enumNames.hasMoreElements()) - { - String name = (String)enumNames.nextElement(); - if (name.endsWith(userKeyPostfix)) - { - userKey = name; - break; - } - } - } - if (userKey != null) - { - SessionUser user = (SessionUser)event.getSession().getAttribute(userKey); - if (user != null) - { - // invalidate ticket and clear the Security context for this thread - WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext); - AuthenticationService authService = (AuthenticationService)ctx.getBean("authenticationService"); - authService.invalidateTicket(user.getTicket(), event.getSession().getId()); - authService.clearCurrentSecurityContext(); - event.getSession().removeAttribute(userKey); - } + // invalidate ticket and clear the Security context for this thread + WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext); + AuthenticationService authService = (AuthenticationService)ctx.getBean("authenticationService"); + authService.invalidateTicket(user.getTicket(), event.getSession().getId()); + authService.clearCurrentSecurityContext(); + event.getSession().removeAttribute(AuthenticationHelper.AUTHENTICATION_USER); } } } diff --git a/source/java/org/alfresco/web/app/portlet/AlfrescoDefaultViewSelector.java b/source/java/org/alfresco/web/app/portlet/AlfrescoDefaultViewSelector.java index 9c94ab59f6..93fcc75418 100644 --- a/source/java/org/alfresco/web/app/portlet/AlfrescoDefaultViewSelector.java +++ b/source/java/org/alfresco/web/app/portlet/AlfrescoDefaultViewSelector.java @@ -20,6 +20,7 @@ package org.alfresco.web.app.portlet; import javax.portlet.PortletContext; import javax.portlet.PortletException; +import javax.portlet.PortletSession; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; @@ -39,7 +40,8 @@ public class AlfrescoDefaultViewSelector implements DefaultViewSelector */ public String selectViewId(RenderRequest request, RenderResponse response) throws PortletException { - User user = (User)request.getPortletSession().getAttribute(AuthenticationHelper.AUTHENTICATION_USER); + User user = (User) request.getPortletSession().getAttribute(AuthenticationHelper.AUTHENTICATION_USER, + PortletSession.APPLICATION_SCOPE); if (user != null && user.getUserName().equals(AuthenticationUtil.getGuestUserName())) { return FacesHelper.BROWSE_VIEW_ID; diff --git a/source/java/org/alfresco/web/app/portlet/AlfrescoFacesPortlet.java b/source/java/org/alfresco/web/app/portlet/AlfrescoFacesPortlet.java index 9df8ffea61..c6758f1862 100644 --- a/source/java/org/alfresco/web/app/portlet/AlfrescoFacesPortlet.java +++ b/source/java/org/alfresco/web/app/portlet/AlfrescoFacesPortlet.java @@ -30,13 +30,19 @@ import javax.faces.component.UIViewRoot; import javax.faces.context.FacesContext; import javax.portlet.ActionRequest; import javax.portlet.ActionResponse; +import javax.portlet.MimeResponse; +import javax.portlet.PortletConfig; import javax.portlet.PortletException; import javax.portlet.PortletRequest; import javax.portlet.PortletRequestDispatcher; +import javax.portlet.PortletResponse; import javax.portlet.PortletSession; import javax.portlet.PortletURL; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; +import javax.portlet.ResourceRequest; +import javax.portlet.ResourceResponse; +import javax.portlet.ResourceURL; import javax.portlet.UnavailableException; import javax.servlet.ServletRequest; @@ -92,15 +98,14 @@ public class AlfrescoFacesPortlet extends MyFacesGenericPortlet public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException { - Application.setInPortalServer(true); - - // Set the current locale - I18NUtil.setLocale(getLanguage(request.getPortletSession())); - - boolean isMultipart = PortletFileUpload.isMultipartContent(request); - + Application.setInPortalServer(true); try { + // Set the current locale + I18NUtil.setLocale(getLanguage(request.getPortletSession())); + + boolean isMultipart = PortletFileUpload.isMultipartContent(request); + // NOTE: Due to filters not being called within portlets we can not make use // of the MyFaces file upload support, therefore we are using a pure // portlet request/action to handle file uploads until there is a @@ -163,8 +168,9 @@ public class AlfrescoFacesPortlet extends MyFacesGenericPortlet } else { - SessionUser sessionUser = (SessionUser)request.getPortletSession().getAttribute(AuthenticationHelper.AUTHENTICATION_USER); - User user = sessionUser instanceof User ? (User)sessionUser : null; + SessionUser sessionUser = (SessionUser) request.getPortletSession().getAttribute( + AuthenticationHelper.AUTHENTICATION_USER, PortletSession.APPLICATION_SCOPE); + User user = sessionUser instanceof User ? (User) sessionUser : null; if (user != null) { // setup the authentication context @@ -199,7 +205,7 @@ public class AlfrescoFacesPortlet extends MyFacesGenericPortlet catch (AuthenticationException authErr) { // remove User object as it's now useless - request.getPortletSession().removeAttribute(AuthenticationHelper.AUTHENTICATION_USER); + request.getPortletSession().removeAttribute(AuthenticationHelper.AUTHENTICATION_USER, PortletSession.APPLICATION_SCOPE); } } else @@ -233,8 +239,31 @@ public class AlfrescoFacesPortlet extends MyFacesGenericPortlet } } } + finally + { + Application.setInPortalServer(false); + } } + + /* (non-Javadoc) + * @see javax.portlet.GenericPortlet#serveResource(javax.portlet.ResourceRequest, javax.portlet.ResourceResponse) + */ + @Override + public void serveResource(ResourceRequest request, ResourceResponse response) throws PortletException, IOException + { + Application.setInPortalServer(true); + try + { + super.serveResource(request, response); + } + finally + { + Application.setInPortalServer(false); + } + } + + /** * @see org.apache.myfaces.portlet.MyFacesGenericPortlet#facesRender(javax.portlet.RenderRequest, javax.portlet.RenderResponse) */ @@ -243,138 +272,146 @@ public class AlfrescoFacesPortlet extends MyFacesGenericPortlet { Application.setInPortalServer(true); - // Set the current locale - I18NUtil.setLocale(getLanguage(request.getPortletSession())); - - if (request.getParameter(ERROR_OCCURRED) != null) - { - String errorPage = getErrorPage(); + try + { + // Set the current locale + I18NUtil.setLocale(getLanguage(request.getPortletSession())); - if (logger.isDebugEnabled()) - logger.debug("An error has occurred, redirecting to error page: " + errorPage); - - response.setContentType("text/html"); - PortletRequestDispatcher dispatcher = getPortletContext().getRequestDispatcher(errorPage); - dispatcher.include(request, response); - } - else - { - WebApplicationContext ctx = (WebApplicationContext)getPortletContext().getAttribute( - WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); - AuthenticationService auth = (AuthenticationService)ctx.getBean("AuthenticationService"); - - // if we have no User object in the session then an HTTP Session timeout must have occured - // use the viewId to check that we are not already on the login page - PortletSession session = request.getPortletSession(); - String viewId = request.getParameter(VIEW_ID); - // keep track of last view id so we can use it as return page from multi-part requests - request.getPortletSession().setAttribute(SESSION_LAST_VIEW_ID, viewId); - SessionUser sessionUser = (SessionUser)request.getPortletSession().getAttribute(AuthenticationHelper.AUTHENTICATION_USER); - User user = sessionUser instanceof User ? (User)sessionUser : null; - if (user == null && (viewId == null || viewId.equals(getLoginPage()) == false)) + if (request.getParameter(ERROR_OCCURRED) != null) { - if (portalGuestAuthenticate(ctx, session, auth) != null) + String errorPage = getErrorPage(); + + if (logger.isDebugEnabled()) + logger.debug("An error has occurred, redirecting to error page: " + errorPage); + + response.setContentType("text/html"); + PortletRequestDispatcher dispatcher = getPortletContext().getRequestDispatcher(errorPage); + dispatcher.include(request, response); + } + else + { + WebApplicationContext ctx = (WebApplicationContext)getPortletContext().getAttribute( + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); + AuthenticationService auth = (AuthenticationService)ctx.getBean("AuthenticationService"); + + // if we have no User object in the session then an HTTP Session timeout must have occured + // use the viewId to check that we are not already on the login page + PortletSession session = request.getPortletSession(); + String viewId = request.getParameter(VIEW_ID); + // keep track of last view id so we can use it as return page from multi-part requests + request.getPortletSession().setAttribute(SESSION_LAST_VIEW_ID, viewId); + SessionUser sessionUser = (SessionUser) request.getPortletSession().getAttribute( + AuthenticationHelper.AUTHENTICATION_USER, PortletSession.APPLICATION_SCOPE); + User user = sessionUser instanceof User ? (User)sessionUser : null; + if (user == null && (viewId == null || viewId.equals(getLoginPage()) == false)) { - if (logger.isDebugEnabled()) - logger.debug("Guest access successful."); - - // perform the forward to the page processed by the Faces servlet - response.setContentType("text/html"); - request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true"); - - // get the start location as configured by the web-client config - ConfigService configService = (ConfigService)ctx.getBean("webClientConfigService"); - ClientConfigElement configElement = (ClientConfigElement)configService.getGlobalConfig().getConfigElement("client"); - if (NavigationBean.LOCATION_MYALFRESCO.equals(configElement.getInitialLocation())) + if (portalGuestAuthenticate(ctx, session, auth) != null) { - nonFacesRequest(request, response, "/jsp/dashboards/container.jsp"); + if (logger.isDebugEnabled()) + logger.debug("Guest access successful."); + + // perform the forward to the page processed by the Faces servlet + response.setContentType("text/html"); + request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true"); + + // get the start location as configured by the web-client config + ConfigService configService = (ConfigService)ctx.getBean("webClientConfigService"); + ClientConfigElement configElement = (ClientConfigElement)configService.getGlobalConfig().getConfigElement("client"); + if (NavigationBean.LOCATION_MYALFRESCO.equals(configElement.getInitialLocation())) + { + nonFacesRequest(request, response, "/jsp/dashboards/container.jsp"); + } + else + { + nonFacesRequest(request, response, FacesHelper.BROWSE_VIEW_ID); + } } else { - nonFacesRequest(request, response, FacesHelper.BROWSE_VIEW_ID); + if (logger.isDebugEnabled()) + logger.debug("No valid User login, requesting login page. ViewId: " + viewId); + + // set last used username as special session value used by the LoginBean + session.setAttribute(AuthenticationHelper.SESSION_USERNAME, + request.getPreferences().getValue(PREF_ALF_USERNAME, null)); + + // login page is the default portal page + response.setContentType("text/html"); + request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true"); + nonFacesRequest(request, response); } } else { - if (logger.isDebugEnabled()) - logger.debug("No valid User login, requesting login page. ViewId: " + viewId); - - // set last used username as special session value used by the LoginBean - session.setAttribute(AuthenticationHelper.SESSION_USERNAME, - request.getPreferences().getValue(PREF_ALF_USERNAME, null)); - - // login page is the default portal page - response.setContentType("text/html"); - request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true"); - nonFacesRequest(request, response); - } - } - else - { - if (session.getAttribute(AuthenticationHelper.SESSION_INVALIDATED) != null) - { - // remove the username preference value as explicit logout was requested by the user - if (request.getPreferences().isReadOnly(PREF_ALF_USERNAME) == false) + if (session.getAttribute(AuthenticationHelper.SESSION_INVALIDATED) != null) { - request.getPreferences().reset(PREF_ALF_USERNAME); - } - session.removeAttribute(AuthenticationHelper.SESSION_INVALIDATED); - } - - try - { - if (user != null) - { - if (logger.isDebugEnabled()) - logger.debug("Validating ticket: " + user.getTicket()); - - // setup the authentication context - auth.validate(user.getTicket(), null); - } - - // do the normal JSF processing - super.facesRender(request, response); - } - catch (AuthenticationException authErr) - { - // ticket is no longer valid! - if (logger.isDebugEnabled()) - logger.debug("Invalid ticket, requesting login page."); - - // remove User object as it's now useless - request.getPortletSession().removeAttribute(AuthenticationHelper.AUTHENTICATION_USER); - - // login page is the default portal page - response.setContentType("text/html"); - request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true"); - nonFacesRequest(request, response); - } - catch (Throwable e) - { - if (getErrorPage() != null) - { - handleError(request, response, e); - } - else - { - logger.warn("No error page configured, re-throwing exception"); - - if (e instanceof PortletException) + // remove the username preference value as explicit logout was requested by the user + if (request.getPreferences().isReadOnly(PREF_ALF_USERNAME) == false) { - throw (PortletException)e; + request.getPreferences().reset(PREF_ALF_USERNAME); } - else if (e instanceof IOException) + session.removeAttribute(AuthenticationHelper.SESSION_INVALIDATED); + } + + try + { + if (user != null) { - throw (IOException)e; + if (logger.isDebugEnabled()) + logger.debug("Validating ticket: " + user.getTicket()); + + // setup the authentication context + auth.validate(user.getTicket(), null); + } + + // do the normal JSF processing + super.facesRender(request, response); + } + catch (AuthenticationException authErr) + { + // ticket is no longer valid! + if (logger.isDebugEnabled()) + logger.debug("Invalid ticket, requesting login page."); + + // remove User object as it's now useless + session.removeAttribute(AuthenticationHelper.AUTHENTICATION_USER, PortletSession.APPLICATION_SCOPE); + + // login page is the default portal page + response.setContentType("text/html"); + request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true"); + nonFacesRequest(request, response); + } + catch (Throwable e) + { + if (getErrorPage() != null) + { + handleError(request, response, e); } else { - throw new PortletException(e); + logger.warn("No error page configured, re-throwing exception"); + + if (e instanceof PortletException) + { + throw (PortletException)e; + } + else if (e instanceof IOException) + { + throw (IOException)e; + } + else + { + throw new PortletException(e); + } } } } } } + finally + { + Application.setInPortalServer(false); + } } /** @@ -406,13 +443,16 @@ public class AlfrescoFacesPortlet extends MyFacesGenericPortlet */ public static ErrorBean getErrorBean(ServletRequest request) { - PortletRequest portletReq = (PortletRequest) request.getAttribute("javax.portlet.request"); + PortletRequest portletReq = (PortletRequest) request.getAttribute("javax.portlet.request"); if (portletReq != null) { - PortletSession session = portletReq.getPortletSession(); - return (ErrorBean)session.getAttribute(ErrorBean.ERROR_BEAN_NAME); + PortletSession session = portletReq.getPortletSession(false); + if (session != null) + { + return (ErrorBean)session.getAttribute(ErrorBean.ERROR_BEAN_NAME); + } } - return null; + return null; } /** @@ -456,6 +496,90 @@ public class AlfrescoFacesPortlet extends MyFacesGenericPortlet } + /** + * Creates a resource URL from the given faces context. + * + * @param context + * the faces context + * @return the resource URL + */ + public static String getResourceURL(FacesContext context, String path) + { + MimeResponse portletResponse = (MimeResponse) context.getExternalContext().getResponse(); + ResourceURL resourceURL = portletResponse.createResourceURL(); + resourceURL.setResourceID(path); + return resourceURL.toString(); + } + + /** + * Gets a session attribute. + * + * @param context + * the faces context + * @param attributeName + * the attribute name + * @param shared + * get the attribute from shared (application) scope? + * @return the portlet session attribute + */ + public static Object getPortletSessionAttribute(FacesContext context, String attributeName, boolean shared) + { + Object portletReq = context.getExternalContext().getRequest(); + if (portletReq != null && portletReq instanceof PortletRequest) + { + PortletSession session = ((PortletRequest) portletReq).getPortletSession(false); + if (session != null) + { + return session.getAttribute(attributeName, shared ? PortletSession.APPLICATION_SCOPE + : PortletSession.PORTLET_SCOPE); + } + } + return null; + } + + /** + * Sets a session attribute. + * + * @param context + * the faces context + * @param attributeName + * the attribute name + * @param value + * the value + * @param shared + * set the attribute with shared (application) scope? + */ + public static void setPortletSessionAttribute(FacesContext context, String attributeName, Object value, + boolean shared) + { + Object portletReq = context.getExternalContext().getRequest(); + if (portletReq != null && portletReq instanceof PortletRequest) + { + PortletSession session = ((PortletRequest) portletReq).getPortletSession(); + session.setAttribute(attributeName, value, shared ? PortletSession.APPLICATION_SCOPE + : PortletSession.PORTLET_SCOPE); + } + else + { + context.getExternalContext().getSessionMap().put(attributeName, value); + } + } + + /** + * Initializes a new faces context using the portlet objects from a 'wrapped' servlet request. + * + * @param request + * the servlet request + * @return the faces context + */ + public static FacesContext getFacesContext(ServletRequest request) + { + PortletRequest portletReq = (PortletRequest) request.getAttribute("javax.portlet.request"); + PortletResponse portletRes = (PortletResponse) request.getAttribute("javax.portlet.response"); + PortletConfig portletConfig = (PortletConfig) request.getAttribute("javax.portlet.config"); + return FacesHelper.getFacesContext(portletReq, portletRes, portletConfig.getPortletContext()); + } + /** * Handles errors that occur during a render request */ @@ -522,7 +646,7 @@ public class AlfrescoFacesPortlet extends MyFacesGenericPortlet if (user != null) { // store the User object in the Session - the authentication servlet will then proceed - session.setAttribute(AuthenticationHelper.AUTHENTICATION_USER, user); + session.setAttribute(AuthenticationHelper.AUTHENTICATION_USER, user, PortletSession.APPLICATION_SCOPE); // Set the current locale I18NUtil.setLocale(getLanguage(session)); diff --git a/source/java/org/alfresco/web/app/servlet/AuthenticationHelper.java b/source/java/org/alfresco/web/app/servlet/AuthenticationHelper.java index a4ac802310..dd623cb6cf 100644 --- a/source/java/org/alfresco/web/app/servlet/AuthenticationHelper.java +++ b/source/java/org/alfresco/web/app/servlet/AuthenticationHelper.java @@ -20,7 +20,6 @@ package org.alfresco.web.app.servlet; import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.util.Enumeration; import javax.faces.context.FacesContext; import javax.servlet.ServletContext; @@ -45,6 +44,7 @@ import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.web.app.Application; +import org.alfresco.web.app.portlet.AlfrescoFacesPortlet; import org.alfresco.web.bean.LoginBean; import org.alfresco.web.bean.repository.User; import org.alfresco.web.bean.users.UserPreferencesBean; @@ -105,7 +105,8 @@ public final class AuthenticationHelper public static void setupThread(ServletContext sc, HttpServletRequest req, HttpServletResponse res) { // setup faces context - FacesContext fc = FacesHelper.getFacesContext(req, res, sc); + FacesContext fc = Application.inPortalServer() ? AlfrescoFacesPortlet.getFacesContext(req) : FacesHelper + .getFacesContext(req, res, sc); // Set the current locale and language if (Application.getClientConfig(fc).isLanguageSelect()) @@ -437,7 +438,6 @@ public final class AuthenticationHelper * The HTTP response * @return The User object representing the current user or null if it could not be found */ - @SuppressWarnings("unchecked") public static User getUser(final ServletContext sc, final HttpServletRequest httpRequest, HttpServletResponse httpResponse) { String userId = null; @@ -454,32 +454,11 @@ public final class AuthenticationHelper User user = null; // examine the appropriate session to try and find the User object - SessionUser sessionUser = null; - String sessionUserAttrib = null; - if (Application.inPortalServer() == false) - { - sessionUserAttrib = AUTHENTICATION_USER; - } - else - { - // naff solution as we need to enumerate all session keys until we find the one that - // should match our User objects - this is weak but we don't know how the underlying - // Portal vendor has decided to encode the objects in the session - Enumeration enumNames = (Enumeration) session.getAttributeNames(); - while (enumNames.hasMoreElements()) - { - String name = enumNames.nextElement(); - if (name.endsWith(AUTHENTICATION_USER)) - { - sessionUserAttrib = name; - break; - } - } - } + SessionUser sessionUser = Application.getCurrentUser(session); // Make sure the ticket is valid, the person exists, and the cached user is of the right type (WebDAV users have // been known to leak in but shouldn't now) - if (sessionUserAttrib != null && (sessionUser = (SessionUser) session.getAttribute(sessionUserAttrib)) != null) + if (sessionUser != null) { AuthenticationService auth = (AuthenticationService) wc.getBean(AUTHENTICATION_SERVICE); try @@ -497,7 +476,7 @@ public final class AuthenticationHelper } catch (AuthenticationException authErr) { - session.removeAttribute(sessionUserAttrib); + session.removeAttribute(AUTHENTICATION_USER); if (!Application.inPortalServer()) { session.invalidate(); @@ -511,7 +490,7 @@ public final class AuthenticationHelper // We have a previously-cached user with the wrong identity - replace them if (user != null && !user.getUserName().equals(userId)) { - session.removeAttribute(sessionUserAttrib); + session.removeAttribute(AUTHENTICATION_USER); if (!Application.inPortalServer()) { session.invalidate(); diff --git a/source/java/org/alfresco/web/app/servlet/UploadFileServlet.java b/source/java/org/alfresco/web/app/servlet/UploadFileServlet.java index 39d7340a8b..9fb6513aae 100644 --- a/source/java/org/alfresco/web/app/servlet/UploadFileServlet.java +++ b/source/java/org/alfresco/web/app/servlet/UploadFileServlet.java @@ -20,16 +20,16 @@ package org.alfresco.web.app.servlet; import java.io.File; import java.io.IOException; import java.io.PrintWriter; -import java.util.Enumeration; import java.util.List; +import java.util.Map; +import javax.faces.context.FacesContext; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.springframework.extensions.config.ConfigService; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.util.TempFileProvider; @@ -45,6 +45,7 @@ import org.apache.commons.fileupload.servlet.ServletRequestContext; import org.apache.commons.io.FilenameUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.config.ConfigService; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; @@ -77,6 +78,7 @@ public class UploadFileServlet extends BaseServlet /** * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ + @SuppressWarnings("unchecked") protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { @@ -102,7 +104,8 @@ public class UploadFileServlet extends BaseServlet if (logger.isDebugEnabled()) logger.debug("Uploading servlet servicing..."); - HttpSession session = request.getSession(); + FacesContext context = FacesContext.getCurrentInstance(); + Map session = context.getExternalContext().getSessionMap(); ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); // ensure that the encoding is handled correctly @@ -162,29 +165,7 @@ public class UploadFileServlet extends BaseServlet } } - // examine the appropriate session to try and find the User object - if (Application.inPortalServer() == false) - { - session.setAttribute(FileUploadBean.getKey(uploadId), bean); - } - else - { - // naff solution as we need to enumerate all session keys until we find the one that - // should match our User objects - this is weak but we don't know how the underlying - // Portal vendor has decided to encode the objects in the session - Enumeration enumNames = session.getAttributeNames(); - while (enumNames.hasMoreElements()) - { - String name = (String)enumNames.nextElement(); - // find an Alfresco value we know must be there... - if (name.startsWith("javax.portlet.p") && name.endsWith(AuthenticationHelper.AUTHENTICATION_USER)) - { - String key = name.substring(0, name.lastIndexOf(AuthenticationHelper.AUTHENTICATION_USER)); - session.setAttribute(key + FileUploadBean.getKey(uploadId), bean); - break; - } - } - } + session.put(FileUploadBean.getKey(uploadId), bean); if (bean.getFile() == null && uploadId != null && logger.isWarnEnabled()) { diff --git a/source/java/org/alfresco/web/bean/LoginBean.java b/source/java/org/alfresco/web/bean/LoginBean.java index 7b48213b17..fbc231f4cb 100644 --- a/source/java/org/alfresco/web/bean/LoginBean.java +++ b/source/java/org/alfresco/web/bean/LoginBean.java @@ -321,7 +321,7 @@ public class LoginBean implements Serializable // put the User object in the Session - the authentication servlet will then allow // the app to continue without redirecting to the login page - session.put(AuthenticationHelper.AUTHENTICATION_USER, user); + Application.setCurrentUser(fc, user); // if a redirect URL has been provided then use that // this allows servlets etc. to provide a URL to return too after a successful login @@ -427,7 +427,7 @@ public class LoginBean implements Serializable else { Map session = context.getExternalContext().getSessionMap(); - SessionUser user = (SessionUser)session.get(AuthenticationHelper.AUTHENTICATION_USER); + SessionUser user = Application.getCurrentUser(context); if (user != null) { // invalidate ticket and clear the Security context for this thread diff --git a/source/java/org/alfresco/web/ui/common/component/UploadInput.java b/source/java/org/alfresco/web/ui/common/component/UploadInput.java index b2c58658fc..a028ae52ed 100644 --- a/source/java/org/alfresco/web/ui/common/component/UploadInput.java +++ b/source/java/org/alfresco/web/ui/common/component/UploadInput.java @@ -25,6 +25,9 @@ import javax.faces.component.UIInput; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; +import org.alfresco.web.app.Application; +import org.alfresco.web.app.portlet.AlfrescoFacesPortlet; + public class UploadInput extends UIInput implements NamingContainer { private static final long serialVersionUID = 4064734856565167835L; @@ -34,16 +37,18 @@ public class UploadInput extends UIInput implements NamingContainer public void encodeBegin(FacesContext context) throws IOException { ResponseWriter writer = context.getResponseWriter(); - String path = context.getExternalContext().getRequestContextPath(); + String contextPath = context.getExternalContext().getRequestContextPath(); + String path = Application.inPortalServer() ? AlfrescoFacesPortlet.getResourceURL(context, "/uploadFileServlet") + : contextPath + "/uploadFileServlet"; writer.write("\n"); writer.write("