diff --git a/source/java/org/alfresco/web/app/portlet/AlfrescoDefaultViewSelector.java b/source/java/org/alfresco/web/app/portlet/AlfrescoDefaultViewSelector.java new file mode 100644 index 0000000000..00f4d6b617 --- /dev/null +++ b/source/java/org/alfresco/web/app/portlet/AlfrescoDefaultViewSelector.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.web.app.portlet; + +import javax.portlet.PortletContext; +import javax.portlet.PortletException; +import javax.portlet.RenderRequest; +import javax.portlet.RenderResponse; + +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.web.app.servlet.AuthenticationHelper; +import org.alfresco.web.bean.repository.User; +import org.apache.myfaces.portlet.DefaultViewSelector; + +/** + * @author Kevin Roast + */ +public class AlfrescoDefaultViewSelector implements DefaultViewSelector +{ + /** + * Select the appropriate view ID + */ + public String selectViewId(RenderRequest request, RenderResponse response) throws PortletException + { + User user = (User)request.getPortletSession().getAttribute(AuthenticationHelper.AUTHENTICATION_USER); + if (user != null && user.getUserName().equals(PermissionService.GUEST)) + { + return "/jsp/browse/browse.jsp"; + } + else + { + return null; + } + } + + /** + * @see org.apache.myfaces.portlet.DefaultViewSelector#setPortletContext(javax.portlet.PortletContext) + */ + public void setPortletContext(PortletContext portletContext) + { + } +} diff --git a/source/java/org/alfresco/web/app/portlet/AlfrescoFacesPortlet.java b/source/java/org/alfresco/web/app/portlet/AlfrescoFacesPortlet.java index 0964370f69..c559ecb9e9 100644 --- a/source/java/org/alfresco/web/app/portlet/AlfrescoFacesPortlet.java +++ b/source/java/org/alfresco/web/app/portlet/AlfrescoFacesPortlet.java @@ -31,6 +31,7 @@ import javax.portlet.PortletRequestDispatcher; import javax.portlet.PortletSession; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; +import javax.portlet.UnavailableException; import org.alfresco.i18n.I18NUtil; import org.alfresco.repo.security.authentication.AuthenticationException; @@ -38,6 +39,7 @@ import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.util.TempFileProvider; import org.alfresco.web.app.Application; import org.alfresco.web.app.servlet.AuthenticationHelper; +import org.alfresco.web.app.servlet.AuthenticationStatus; import org.alfresco.web.bean.ErrorBean; import org.alfresco.web.bean.FileUploadBean; import org.alfresco.web.bean.LoginBean; @@ -242,6 +244,10 @@ public class AlfrescoFacesPortlet extends MyFacesGenericPortlet } 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(); @@ -249,17 +255,30 @@ public class AlfrescoFacesPortlet extends MyFacesGenericPortlet User user = (User)request.getPortletSession().getAttribute(AuthenticationHelper.AUTHENTICATION_USER); if (user == null && (viewId == null || viewId.equals(getLoginPage()) == false)) { - 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 redirect - response.setContentType("text/html"); - request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true"); - nonFacesRequest(request, response); + if (AuthenticationHelper.portalGuestAuthenticate(ctx, session, auth) == AuthenticationStatus.Guest) + { + 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"); + nonFacesRequest(request, response, "/jsp/browse/browse.jsp"); + } + 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 { @@ -278,9 +297,6 @@ public class AlfrescoFacesPortlet extends MyFacesGenericPortlet logger.debug("Validating ticket: " + user.getTicket()); // setup the authentication context - WebApplicationContext ctx = (WebApplicationContext)getPortletContext().getAttribute( - WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); - AuthenticationService auth = (AuthenticationService)ctx.getBean("authenticationService"); auth.validate(user.getTicket()); } @@ -296,7 +312,7 @@ public class AlfrescoFacesPortlet extends MyFacesGenericPortlet // remove User object as it's now useless request.getPortletSession().removeAttribute(AuthenticationHelper.AUTHENTICATION_USER); - // login page redirect + // login page is the default portal page response.setContentType("text/html"); request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true"); nonFacesRequest(request, response); @@ -390,6 +406,18 @@ public class AlfrescoFacesPortlet extends MyFacesGenericPortlet dispatcher.include(request, response); } + /** + * @see org.apache.myfaces.portlet.MyFacesGenericPortlet#setDefaultViewSelector() + */ + protected void setDefaultViewSelector() throws UnavailableException + { + super.setDefaultViewSelector(); + if (this.defaultViewSelector == null) + { + this.defaultViewSelector = new AlfrescoDefaultViewSelector(); + } + } + /** * @return Retrieves the configured login page */ diff --git a/source/java/org/alfresco/web/app/servlet/AuthenticationHelper.java b/source/java/org/alfresco/web/app/servlet/AuthenticationHelper.java index df5b546ce0..e91e675d14 100644 --- a/source/java/org/alfresco/web/app/servlet/AuthenticationHelper.java +++ b/source/java/org/alfresco/web/app/servlet/AuthenticationHelper.java @@ -18,6 +18,7 @@ package org.alfresco.web.app.servlet; import java.io.IOException; +import javax.portlet.PortletSession; import javax.servlet.ServletContext; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; @@ -37,6 +38,7 @@ import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.transaction.TransactionService; import org.alfresco.web.app.Application; import org.alfresco.web.app.portlet.AlfrescoFacesPortlet; import org.alfresco.web.bean.LoginBean; @@ -250,6 +252,80 @@ public final class AuthenticationHelper return AuthenticationStatus.Success; } + /** + * For no previous authentication or forced Guest - attempt Guest access + * + * @param ctx WebApplicationContext + * @param auth AuthenticationService + */ + public static AuthenticationStatus portalGuestAuthenticate(WebApplicationContext ctx, PortletSession session, AuthenticationService auth) + { + UserTransaction tx = null; + try + { + auth.authenticateAsGuest(); + + // if we get here then Guest access was allowed and successful + ServiceRegistry services = (ServiceRegistry)ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); + tx = services.getTransactionService().getUserTransaction(); + tx.begin(); + + NodeService nodeService = services.getNodeService(); + PersonService personService = (PersonService)ctx.getBean(PERSON_SERVICE); + NodeRef guestRef = personService.getPerson(PermissionService.GUEST); + User user = new User(PermissionService.GUEST, auth.getCurrentTicket(), guestRef); + NodeRef guestHomeRef = (NodeRef)nodeService.getProperty(guestRef, ContentModel.PROP_HOMEFOLDER); + + // check that the home space node exists - else Guest cannot proceed + if (nodeService.exists(guestHomeRef) == false) + { + throw new InvalidNodeRefException(guestHomeRef); + } + user.setHomeSpaceId(guestHomeRef.getId()); + + tx.commit(); + tx = null; // clear this so we know not to rollback + + // store the User object in the Session - the authentication servlet will then proceed + session.setAttribute(AuthenticationHelper.AUTHENTICATION_USER, user); + + // Set the current locale + I18NUtil.setLocale(Application.getLanguage(session)); + + // remove the session invalidated flag + session.removeAttribute(AuthenticationHelper.SESSION_INVALIDATED); + + // it is the responsibilty of the caller to handle the Guest return status + return AuthenticationStatus.Guest; + } + catch (AuthenticationException guestError) + { + // Expected if Guest access not allowed - continue to login page as usual + } + catch (AccessDeniedException accessError) + { + // Guest is unable to access either properties on Person + AuthenticationService unprotAuthService = (AuthenticationService)ctx.getBean(UNPROTECTED_AUTH_SERVICE); + unprotAuthService.invalidateTicket(unprotAuthService.getCurrentTicket()); + unprotAuthService.clearCurrentSecurityContext(); + logger.warn("Unable to login as Guest: " + accessError.getMessage()); + } + catch (Throwable e) + { + // Some other kind of serious failure to report + AuthenticationService unprotAuthService = (AuthenticationService)ctx.getBean(UNPROTECTED_AUTH_SERVICE); + unprotAuthService.invalidateTicket(unprotAuthService.getCurrentTicket()); + unprotAuthService.clearCurrentSecurityContext(); + throw new AlfrescoRuntimeException("Failed to authenticate as Guest user.", e); + } + finally + { + try { if (tx != null) {tx.rollback();} } catch (Exception tex) {} + } + + return AuthenticationStatus.Failure; + } + /** * Setup the Alfresco auth cookie value. * diff --git a/source/java/org/alfresco/web/app/servlet/ExternalAccessServlet.java b/source/java/org/alfresco/web/app/servlet/ExternalAccessServlet.java index dfd980121a..5f0424c03c 100644 --- a/source/java/org/alfresco/web/app/servlet/ExternalAccessServlet.java +++ b/source/java/org/alfresco/web/app/servlet/ExternalAccessServlet.java @@ -31,7 +31,6 @@ import org.alfresco.repo.webdav.WebDAVServlet; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.web.bean.BrowseBean; -import org.alfresco.web.bean.NavigationBean; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -104,7 +103,7 @@ public class ExternalAccessServlet extends HttpServlet logger.debug("External outcome found: " + outcome); // we almost always need this bean reference - FacesContext fc = ServletHelper.getFacesContext(req, res, getServletContext()); + FacesContext fc = FacesHelper.getFacesContext(req, res, getServletContext()); BrowseBean browseBean = (BrowseBean)ServletHelper.getManagedBean(fc, "BrowseBean"); // setup is required for certain outcome requests diff --git a/source/java/org/alfresco/web/app/servlet/FacesHelper.java b/source/java/org/alfresco/web/app/servlet/FacesHelper.java new file mode 100644 index 0000000000..5640082d10 --- /dev/null +++ b/source/java/org/alfresco/web/app/servlet/FacesHelper.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.web.app.servlet; + +import javax.faces.FactoryFinder; +import javax.faces.component.UIViewRoot; +import javax.faces.context.FacesContext; +import javax.faces.context.FacesContextFactory; +import javax.faces.lifecycle.Lifecycle; +import javax.faces.lifecycle.LifecycleFactory; + +/** + * @author Kevin Roast + */ +public final class FacesHelper +{ + /** + * Private constructor + */ + private FacesHelper() + { + } + + /** + * Return a valid FacesContext for the specific context, request and response. + * The FacesContext can be constructor for Servlet and Portlet use. + * + * @param context ServletContext or PortletContext + * @param request ServletRequest or PortletRequest + * @param response ServletReponse or PortletResponse + * + * @return FacesContext + */ + public static FacesContext getFacesContext(Object context, Object request, Object response) + { + FacesContext facesContext = FacesContext.getCurrentInstance(); + if (facesContext != null) return facesContext; + + FacesContextFactory contextFactory = (FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY); + LifecycleFactory lifecycleFactory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY); + Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE); + + // Doesn't set this instance as the current instance of FacesContext.getCurrentInstance + facesContext = contextFactory.getFacesContext(context, request, response, lifecycle); + + // Set using our inner class + InnerFacesContext.setFacesContextAsCurrent(facesContext); + + // set a new viewRoot, otherwise context.getViewRoot returns null + UIViewRoot view = facesContext.getApplication().getViewHandler().createView(facesContext, "/jsp/root"); + facesContext.setViewRoot(view); + + return facesContext; + } + + /** + * We need an inner class to be able to call FacesContext.setCurrentInstance + * since it's a protected method + */ + private abstract static class InnerFacesContext extends FacesContext + { + protected static void setFacesContextAsCurrent(FacesContext facesContext) + { + FacesContext.setCurrentInstance(facesContext); + } + } +} diff --git a/source/java/org/alfresco/web/app/servlet/ServletHelper.java b/source/java/org/alfresco/web/app/servlet/ServletHelper.java index 1d3cc27b44..ff54d68d41 100644 --- a/source/java/org/alfresco/web/app/servlet/ServletHelper.java +++ b/source/java/org/alfresco/web/app/servlet/ServletHelper.java @@ -22,16 +22,9 @@ import java.net.URLDecoder; import java.util.ArrayList; import java.util.List; -import javax.faces.FactoryFinder; -import javax.faces.component.UIViewRoot; import javax.faces.context.FacesContext; -import javax.faces.context.FacesContextFactory; import javax.faces.el.ValueBinding; -import javax.faces.lifecycle.Lifecycle; -import javax.faces.lifecycle.LifecycleFactory; import javax.servlet.ServletContext; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -124,49 +117,6 @@ public final class ServletHelper return status; } - /** - * Return FacesContext made available to servlets and servlet filters. - * {@link http://www.thoughtsabout.net/blog/archives/000033.html} - * - * @return FacesContext - */ - public static FacesContext getFacesContext(ServletRequest req, ServletResponse res, ServletContext sc) - { - FacesContext facesContext = FacesContext.getCurrentInstance(); - if (facesContext != null) return facesContext; - - FacesContextFactory contextFactory = (FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY); - LifecycleFactory lifecycleFactory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY); - Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE); - - // Can get ServletContext here like this: - // ServletContext servletContext = ((HttpServletRequest)request).getSession().getServletContext(); - - // Doesn't set this instance as the current instance of FacesContext.getCurrentInstance - facesContext = contextFactory.getFacesContext(sc, req, res, lifecycle); - - // Set using our inner class - InnerFacesContext.setFacesContextAsCurrent(facesContext); - - // set a new viewRoot, otherwise context.getViewRoot returns null - UIViewRoot view = facesContext.getApplication().getViewHandler().createView(facesContext, "/jsp/root"); - facesContext.setViewRoot(view); - - return facesContext; - } - - /** - * We need an inner class to be able to call FacesContext.setCurrentInstance - * since it's a protected method - */ - private abstract static class InnerFacesContext extends FacesContext - { - protected static void setFacesContextAsCurrent(FacesContext facesContext) - { - FacesContext.setCurrentInstance(facesContext); - } - } - /** * Return a JSF managed bean reference. * @@ -210,7 +160,6 @@ public final class ServletHelper Application.getCompanyRootId()); WebApplicationContext wc = FacesContextUtils.getRequiredWebApplicationContext(context); - //WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(context); FileFolderService ffs = (FileFolderService)wc.getBean("FileFolderService"); file = ffs.resolveNamePath(companyHome, paths); nodeRef = file.getNodeRef();