. Guest access check-point

. Fixes to document/space details screen when expanding/collapsing the Links panel
. Fix to Saved Searches to handle AuthenticationException for Guest user access to saved searches folder
. Fix to New User and Edit Password dialogs to fire text changed events when paste is used to fill in form fields

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2164 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Kevin Roast
2006-01-20 17:15:32 +00:00
parent 3e5aa0c84a
commit 2c367a0a33
17 changed files with 174 additions and 57 deletions

View File

@@ -64,7 +64,10 @@ public class AuthenticationFilter implements Filter
// allow the login page to proceed
if (httpReq.getRequestURI().endsWith(getLoginPage()) == false)
{
if (AuthenticationHelper.authenticate(this.context, httpReq, (HttpServletResponse)res))
AuthenticationStatus status =
AuthenticationHelper.authenticate(this.context, httpReq, (HttpServletResponse)res);
if (status == AuthenticationStatus.Success || status == AuthenticationStatus.Guest)
{
// continue filter chaining
chain.doFilter(req, res);

View File

@@ -22,10 +22,20 @@ import javax.servlet.ServletContext;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.transaction.UserTransaction;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
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;
@@ -54,45 +64,105 @@ public final class AuthenticationHelper
* User information is looked up in the Session. If found the ticket is retrieved and validated.
* If no User info is found or the ticket is invalid then a redirect is performed to the login page.
*
* @return true if authentication successful, false otherwise.
* @return AuthenticationStatus result.
*/
public static boolean authenticate(ServletContext context, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
throws IOException
public static AuthenticationStatus authenticate(
ServletContext context, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
throws IOException
{
HttpSession session = httpRequest.getSession();
// examine the appropriate session for our User object
User user;
LoginBean loginBean = null;
if (Application.inPortalServer() == false)
{
user = (User)httpRequest.getSession().getAttribute(AUTHENTICATION_USER);
loginBean = (LoginBean)httpRequest.getSession().getAttribute(LOGIN_BEAN);
user = (User)session.getAttribute(AUTHENTICATION_USER);
loginBean = (LoginBean)session.getAttribute(LOGIN_BEAN);
}
else
{
user = (User)httpRequest.getSession().getAttribute(AlfrescoFacesPortlet.MANAGED_BEAN_PREFIX + AUTHENTICATION_USER);
user = (User)session.getAttribute(AlfrescoFacesPortlet.MANAGED_BEAN_PREFIX + AUTHENTICATION_USER);
}
// setup the authentication context
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
AuthenticationService auth = (AuthenticationService)ctx.getBean(AUTHENTICATION_SERVICE);
if (user == null)
{
// no user/ticket found - redirect to login page
if (session.getAttribute(AuthenticationHelper.SESSION_INVALIDATED) == null)
{
Cookie authCookie = getAuthCookie(httpRequest);
if (authCookie == null)
{
// TODO: "forced" guest access on URLs!
// no previous authentication - attempt Guest access first
UserTransaction tx = null;
try
{
auth.authenticateAsGuest();
// if we get here then Guest access was allowed and successful
tx = ((TransactionService)ctx.getBean("TransactionService")).getUserTransaction();
tx.begin();
PersonService personService = (PersonService)ctx.getBean("personService");
NodeService nodeService = (NodeService)ctx.getBean("nodeService");
NodeRef guestRef = personService.getPerson(PermissionService.GUEST);
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();
// 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(httpRequest.getSession()));
return AuthenticationStatus.Guest;
// TODO: What now? Any redirects can be performed directly from the appropriate
// servlet entry points, as we are now authenticated and don't
// need to go through the Login screen to gain authentication.
}
catch (AuthenticationException guestError)
{
// Guest access not allowed - continue to login page as usual
}
catch (Throwable e)
{
// Guest access not allowed - some other kind of serious failure to report
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
throw new AlfrescoRuntimeException("Failed to authenticate as Guest user.", e);
}
}
}
// no user/ticket found or session invalidated by user (logout) - redirect to login page
httpResponse.sendRedirect(httpRequest.getContextPath() + "/faces" + Application.getLoginPage(context));
return false;
return AuthenticationStatus.Failure;
}
else
{
// setup the authentication context
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
AuthenticationService auth = (AuthenticationService)ctx.getBean(AUTHENTICATION_SERVICE);
try
{
auth.validate(user.getTicket());
}
catch (AuthenticationException authErr)
{
// no user/ticket - redirect to login page
// expired ticket - redirect to login page
httpResponse.sendRedirect(httpRequest.getContextPath() + "/faces" + Application.getLoginPage(context));
return false;
return AuthenticationStatus.Failure;
}
// set last authentication username cookie value
@@ -104,7 +174,7 @@ public final class AuthenticationHelper
// Set the current locale
I18NUtil.setLocale(Application.getLanguage(httpRequest.getSession()));
return true;
return AuthenticationStatus.Success;
}
}
@@ -113,8 +183,9 @@ public final class AuthenticationHelper
*
* @return true if authentication successful, false otherwise.
*/
public static boolean authenticate(ServletContext context, HttpServletRequest httpRequest, HttpServletResponse httpResponse, String ticket)
throws IOException
public static AuthenticationStatus authenticate(
ServletContext context, HttpServletRequest httpRequest, HttpServletResponse httpResponse, String ticket)
throws IOException
{
// setup the authentication context
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
@@ -125,13 +196,13 @@ public final class AuthenticationHelper
}
catch (AuthenticationException authErr)
{
return false;
return AuthenticationStatus.Failure;
}
// Set the current locale
I18NUtil.setLocale(Application.getLanguage(httpRequest.getSession()));
return true;
return AuthenticationStatus.Success;
}
/**

View File

@@ -0,0 +1,25 @@
/*
* 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;
/**
* @author Kevin Roast
*/
public enum AuthenticationStatus
{
Success, Failure, Guest;
}

View File

@@ -110,20 +110,22 @@ public class DownloadContentServlet extends HttpServlet
logger.debug("Processing URL: " + uri + (req.getQueryString() != null ? ("?" + req.getQueryString()) : ""));
// see if a ticket has been supplied
AuthenticationStatus status;
String ticket = req.getParameter(ARG_TICKET);
if (ticket == null || ticket.length() == 0)
{
if (AuthenticationHelper.authenticate(getServletContext(), req, res) == false)
{
// authentication failed - no point returning the content as we haven't logged in yet
// so end servlet execution and save the URL so the login page knows what to do later
req.getSession().setAttribute(LoginBean.LOGIN_REDIRECT_KEY, uri);
return;
}
status = AuthenticationHelper.authenticate(getServletContext(), req, res);
}
else
{
AuthenticationHelper.authenticate(getServletContext(), req, res, ticket);
status = AuthenticationHelper.authenticate(getServletContext(), req, res, ticket);
}
if (status == AuthenticationStatus.Failure)
{
// authentication failed - no point returning the content as we haven't logged in yet
// so end servlet execution and save the URL so the login page knows what to do later
req.getSession().setAttribute(LoginBean.LOGIN_REDIRECT_KEY, uri);
return;
}
// TODO: add compression here?

View File

@@ -56,7 +56,7 @@ public class ExternalAccessServlet extends HttpServlet
protected void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
boolean alreadyAuthenticated = AuthenticationHelper.authenticate(getServletContext(), req, res);
AuthenticationStatus status = AuthenticationHelper.authenticate(getServletContext(), req, res);
// The URL contains multiple parts
// /alfresco/navigate/<outcome>
@@ -89,7 +89,7 @@ public class ExternalAccessServlet extends HttpServlet
// set the args if any
req.getSession().setAttribute(LoginBean.LOGIN_OUTCOME_ARGS, tokens);
if (alreadyAuthenticated)
if (status == AuthenticationStatus.Success || status == AuthenticationStatus.Guest)
{
// clear the User object from the Session - this will force a relogin
// we do this so the outcome from the login page can then be changed

View File

@@ -96,20 +96,22 @@ public class TemplateContentServlet extends HttpServlet
logger.debug("Processing URL: " + uri + (req.getQueryString() != null ? ("?" + req.getQueryString()) : ""));
// see if a ticket has been supplied
AuthenticationStatus status;
String ticket = req.getParameter(ARG_TICKET);
if (ticket == null || ticket.length() == 0)
{
if (AuthenticationHelper.authenticate(getServletContext(), req, res) == false)
{
// authentication failed - no point returning the content as we haven't logged in yet
// so end servlet execution and save the URL so the login page knows what to do later
req.getSession().setAttribute(LoginBean.LOGIN_REDIRECT_KEY, uri);
return;
}
status = AuthenticationHelper.authenticate(getServletContext(), req, res);
}
else
{
AuthenticationHelper.authenticate(getServletContext(), req, res, ticket);
status = AuthenticationHelper.authenticate(getServletContext(), req, res, ticket);
}
if (status == AuthenticationStatus.Failure)
{
// authentication failed - no point returning the content as we haven't logged in yet
// so end servlet execution and save the URL so the login page knows what to do later
req.getSession().setAttribute(LoginBean.LOGIN_REDIRECT_KEY, uri);
return;
}
StringTokenizer t = new StringTokenizer(uri, "/");

View File

@@ -1302,7 +1302,7 @@ public class AdvancedSearchBean
{
userSearchesRef = results.get(0);
}
else if (results.size() == 0)
else if (results.size() == 0 && new Node(globalRef).hasPermission(PermissionService.ADD_CHILDREN))
{
// attempt to create folder for this user for first time
// create the preferences Node for this user

View File

@@ -278,12 +278,17 @@ public class LoginBean
if (this.username != null && this.password != null)
{
// Authenticate via the authentication service, then save the details of user in an object
// in the session - this is used by the servlet filter etc. on each page to check for login
try
{
Map session = fc.getExternalContext().getSessionMap();
// Authenticate via the authentication service, then save the details of user in an object
// in the session - this is used by the servlet filter etc. on each page to check for login
this.authenticationService.authenticate(this.username, this.password.toCharArray());
// remove the session invalidated flag (used to remove last username cookie by AuthenticationFilter)
session.remove(AuthenticationHelper.SESSION_INVALIDATED);
// setup User object and Home space ID
User user = new User(this.authenticationService.getCurrentUserName(), this.authenticationService.getCurrentTicket(),
personService.getPerson(this.username));
@@ -298,7 +303,6 @@ public class LoginBean
// put the User object in the Session - the authentication servlet will then allow
// the app to continue without redirecting to the login page
Map session = fc.getExternalContext().getSessionMap();
session.put(AuthenticationHelper.AUTHENTICATION_USER, user);
// if an external outcome has been provided then use that, else use default

View File

@@ -39,6 +39,7 @@ import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.web.app.AlfrescoNavigationHandler;
import org.alfresco.web.app.Application;
@@ -406,6 +407,14 @@ public class NavigationBean
this.location = location;
}
/**
* @return true if we are currently the special Guest user
*/
public boolean getIsGuest()
{
return Application.getCurrentUser(FacesContext.getCurrentInstance()).getUserName().equals(PermissionService.GUEST);
}
/**
* Sets up the dispatch context so that the navigation handler knows
* what object is being acted upon

View File

@@ -250,10 +250,10 @@
<a:actionLink value="#{msg.download_content}" href="#{DocumentDetailsBean.downloadUrl}" target="new" id="link4" />
</td>
<td>
<a href='<h:outputText value="#{DocumentDetailsBean.bookmarkUrl}" escape="false" />' onclick="return false;"><h:outputText value="#{msg.details_page_bookmark}" /></a>
<a href='<h:outputText value="#{DocumentDetailsBean.bookmarkUrl}" escape="false" id="out1" />' onclick="return false;"><h:outputText value="#{msg.details_page_bookmark}" id="out2" /></a>
</td>
<td>
<a href='<h:outputText value="#{DocumentDetailsBean.nodeRefUrl}" escape="false" />' onclick="return false;"><h:outputText value="#{msg.noderef_link}" /></a>
<a href='<h:outputText value="#{DocumentDetailsBean.nodeRefUrl}" escape="false" id="out3" />' onclick="return false;"><h:outputText value="#{msg.noderef_link}" id="out4" /></a>
</td>
</tr>
</table>

View File

@@ -248,10 +248,10 @@
<a:actionLink value="#{msg.view_in_cifs}" href="#{SpaceDetailsBean.cifsPath}" target="new" id="link2" />
</td>
<td>
<a href='<h:outputText value="#{SpaceDetailsBean.bookmarkUrl}" escape="false" />' onclick="return false;"><h:outputText value="#{msg.details_page_bookmark}" /></a>
<a href='<h:outputText value="#{SpaceDetailsBean.bookmarkUrl}" escape="false" id="out1" />' onclick="return false;"><h:outputText value="#{msg.details_page_bookmark}" id="out2" /></a>
</td>
<td>
<a href='<h:outputText value="#{SpaceDetailsBean.nodeRefUrl}" escape="false" />' onclick="return false;"><h:outputText value="#{msg.noderef_link}" /></a>
<a href='<h:outputText value="#{SpaceDetailsBean.nodeRefUrl}" escape="false" id="out3" />' onclick="return false;"><h:outputText value="#{msg.noderef_link}" id="out4" /></a>
</td>
</tr>
</table>

View File

@@ -37,7 +37,6 @@
authCookie.setMaxAge(0);
response.addCookie(authCookie);
}
session.removeAttribute(AuthenticationHelper.SESSION_INVALIDATED);
}
else
{

View File

@@ -46,7 +46,10 @@
<td><img src="<%=request.getContextPath()%>/images/icons/Help_icon.gif" width=15 height=15></td>
<td><nobr><h:outputLink value="#{NavigationBean.helpUrl}"><h:outputText value="#{msg.help}" /></h:outputLink></nobr></td>
<td width=8>&nbsp;</td>
<td><nobr><a:actionLink value="#{msg.logout} (#{NavigationBean.currentUser.userName})" action="#{LoginBean.logout}" /></nobr></td>
<td><nobr>
<a:actionLink id="logout" image="/images/icons/logout.gif" value="#{msg.logout} (#{NavigationBean.currentUser.userName})" rendered="#{NavigationBean.isGuest == false}" action="#{LoginBean.logout}" />
<a:actionLink id="login" image="/images/icons/login.gif" value="#{msg.login} (#{NavigationBean.currentUser.userName})" rendered="#{NavigationBean.isGuest == true}" action="#{LoginBean.logout}" />
</nobr></td>
</tr>
</table>
</td>

View File

@@ -36,7 +36,6 @@
authCookie.setMaxAge(0);
response.addCookie(authCookie);
}
session.removeAttribute(AuthenticationHelper.SESSION_INVALIDATED);
}
%>

View File

@@ -137,14 +137,14 @@
<tr>
<td><h:outputText value="#{msg.password}"/>:</td>
<td>
<h:inputSecret id="password" value="#{UsersBean.password}" size="35" maxlength="1024" validator="#{LoginBean.validatePassword}" onkeyup="updateButtonState();" redisplay="true" />&nbsp;*
<h:inputSecret id="password" value="#{UsersBean.password}" size="35" maxlength="1024" validator="#{LoginBean.validatePassword}" onkeyup="updateButtonState();" onchange="updateButtonState();" redisplay="true" />&nbsp;*
&nbsp;<h:message id="errors1" for="password" style="color:red" />
</td>
</tr>
<tr>
<td><h:outputText value="#{msg.confirm}"/>:</td>
<td>
<h:inputSecret id="confirm" value="#{UsersBean.confirm}" size="35" maxlength="1024" validator="#{LoginBean.validatePassword}" onkeyup="updateButtonState();" redisplay="true" />&nbsp;*
<h:inputSecret id="confirm" value="#{UsersBean.confirm}" size="35" maxlength="1024" validator="#{LoginBean.validatePassword}" onkeyup="updateButtonState();" onchange="updateButtonState();" redisplay="true" />&nbsp;*
&nbsp;<h:message id="errors2" for="confirm" style="color:red" />
</td>
</tr>

View File

@@ -151,19 +151,19 @@
<tr>
<td><h:outputText value="#{msg.first_name}"/>:</td>
<td>
<h:inputText id="firstName" value="#{NewUserWizard.firstName}" size="35" maxlength="1024" onkeyup="updateButtonState();" />&nbsp;*
<h:inputText id="firstName" value="#{NewUserWizard.firstName}" size="35" maxlength="1024" onkeyup="updateButtonState();" onchange="updateButtonState();" />&nbsp;*
</td>
</tr>
<tr>
<td><h:outputText value="#{msg.last_name}"/>:</td>
<td>
<h:inputText id="lastName" value="#{NewUserWizard.lastName}" size="35" maxlength="1024" onkeyup="updateButtonState();" />&nbsp;*
<h:inputText id="lastName" value="#{NewUserWizard.lastName}" size="35" maxlength="1024" onkeyup="updateButtonState();" onchange="updateButtonState();" />&nbsp;*
</td>
</tr>
<tr>
<td><h:outputText value="#{msg.email}"/>:</td>
<td>
<h:inputText id="email" value="#{NewUserWizard.email}" size="35" maxlength="1024" onkeyup="updateButtonState();" />&nbsp;*
<h:inputText id="email" value="#{NewUserWizard.email}" size="35" maxlength="1024" onkeyup="updateButtonState();" onchange="updateButtonState();" />&nbsp;*
</td>
</tr>

View File

@@ -170,21 +170,21 @@
<tr>
<td><h:outputText value="#{msg.username}"/>:</td>
<td>
<h:inputText id="userName" value="#{NewUserWizard.userName}" size="35" maxlength="1024" validator="#{LoginBean.validateUsername}" onkeyup="updateButtonState();" disabled="#{NewUserWizard.editMode}" />&nbsp;*
<h:inputText id="userName" value="#{NewUserWizard.userName}" size="35" maxlength="1024" validator="#{LoginBean.validateUsername}" onkeyup="updateButtonState();" onchange="updateButtonState();" disabled="#{NewUserWizard.editMode}" />&nbsp;*
&nbsp;<h:message id="errors1" for="userName" style="color:red" />
</td>
</tr>
<tr>
<td><h:outputText value="#{msg.password}"/>:</td>
<td>
<h:inputSecret id="password" value="#{NewUserWizard.password}" size="35" maxlength="1024" validator="#{LoginBean.validatePassword}" onkeyup="updateButtonState();" disabled="#{NewUserWizard.editMode}" redisplay="true" />&nbsp;*
<h:inputSecret id="password" value="#{NewUserWizard.password}" size="35" maxlength="1024" validator="#{LoginBean.validatePassword}" onkeyup="updateButtonState();" onchange="updateButtonState();" disabled="#{NewUserWizard.editMode}" redisplay="true" />&nbsp;*
&nbsp;<h:message id="errors2" for="password" style="color:red" />
</td>
</tr>
<tr>
<td><h:outputText value="#{msg.confirm}"/>:</td>
<td>
<h:inputSecret id="confirm" value="#{NewUserWizard.confirm}" size="35" maxlength="1024" validator="#{LoginBean.validatePassword}" onkeyup="updateButtonState();" disabled="#{NewUserWizard.editMode}" redisplay="true" />&nbsp;*
<h:inputSecret id="confirm" value="#{NewUserWizard.confirm}" size="35" maxlength="1024" validator="#{LoginBean.validatePassword}" onkeyup="updateButtonState();" onchange="updateButtonState();" disabled="#{NewUserWizard.editMode}" redisplay="true" />&nbsp;*
&nbsp;<h:message id="errors3" for="confirm" style="color:red" />
</td>
</tr>
@@ -202,7 +202,7 @@
<tr>
<td><h:outputText value="#{msg.home_space_name}"/>:</td>
<td>
<h:inputText id="homeSpaceName" value="#{NewUserWizard.homeSpaceName}" size="35" maxlength="1024" onkeyup="updateButtonState();" />
<h:inputText id="homeSpaceName" value="#{NewUserWizard.homeSpaceName}" size="35" maxlength="1024" onkeyup="updateButtonState();" onchange="updateButtonState();" />
</td>
</tr>