mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2140 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
589 lines
21 KiB
Java
589 lines
21 KiB
Java
/*
|
|
* 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.bean;
|
|
|
|
import java.io.IOException;
|
|
import java.io.UnsupportedEncodingException;
|
|
import java.net.URLDecoder;
|
|
import java.text.MessageFormat;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.Map;
|
|
|
|
import javax.faces.application.FacesMessage;
|
|
import javax.faces.component.UIComponent;
|
|
import javax.faces.context.FacesContext;
|
|
import javax.faces.model.SelectItem;
|
|
import javax.faces.validator.ValidatorException;
|
|
import javax.portlet.PortletRequest;
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
|
import org.alfresco.config.ConfigService;
|
|
import org.alfresco.model.ContentModel;
|
|
import org.alfresco.repo.security.authentication.AuthenticationException;
|
|
import org.alfresco.repo.webdav.WebDAVServlet;
|
|
import org.alfresco.service.cmr.model.FileFolderService;
|
|
import org.alfresco.service.cmr.model.FileInfo;
|
|
import org.alfresco.service.cmr.model.FileNotFoundException;
|
|
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
|
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.AuthenticationService;
|
|
import org.alfresco.service.cmr.security.PersonService;
|
|
import org.alfresco.web.app.Application;
|
|
import org.alfresco.web.app.servlet.AuthenticationHelper;
|
|
import org.alfresco.web.bean.repository.Repository;
|
|
import org.alfresco.web.bean.repository.User;
|
|
import org.alfresco.web.config.ClientConfigElement;
|
|
import org.alfresco.web.ui.common.Utils;
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.LogFactory;
|
|
|
|
/**
|
|
* JSF Managed Bean. Backs the "login.jsp" view to provide the form fields used
|
|
* to enter user data for login. Also contains bean methods to validate form
|
|
* fields and action event fired in response to the Login button being pressed.
|
|
*
|
|
* @author Kevin Roast
|
|
*/
|
|
public class LoginBean
|
|
{
|
|
// ------------------------------------------------------------------------------
|
|
// Managed bean properties
|
|
|
|
/**
|
|
* @param authenticationService The AuthenticationService to set.
|
|
*/
|
|
public void setAuthenticationService(AuthenticationService authenticationService)
|
|
{
|
|
this.authenticationService = authenticationService;
|
|
}
|
|
|
|
/**
|
|
* @param personService The personService to set.
|
|
*/
|
|
public void setPersonService(PersonService personService)
|
|
{
|
|
this.personService = personService;
|
|
}
|
|
|
|
/**
|
|
* @param nodeService The nodeService to set.
|
|
*/
|
|
public void setNodeService(NodeService nodeService)
|
|
{
|
|
this.nodeService = nodeService;
|
|
}
|
|
|
|
/**
|
|
* @param browseBean The BrowseBean to set.
|
|
*/
|
|
public void setBrowseBean(BrowseBean browseBean)
|
|
{
|
|
this.browseBean = browseBean;
|
|
}
|
|
|
|
/**
|
|
* @param navigator The NavigationBean to set.
|
|
*/
|
|
public void setNavigator(NavigationBean navigator)
|
|
{
|
|
this.navigator = navigator;
|
|
}
|
|
|
|
/**
|
|
* @param configService The ConfigService to set.
|
|
*/
|
|
public void setConfigService(ConfigService configService)
|
|
{
|
|
this.configService = configService;
|
|
}
|
|
|
|
/**
|
|
* @param fileFolderService The FileFolderService to set.
|
|
*/
|
|
public void setFileFolderService(FileFolderService fileFolderService)
|
|
{
|
|
this.fileFolderService = fileFolderService;
|
|
}
|
|
|
|
/**
|
|
* @param val Username from login dialog
|
|
*/
|
|
public void setUsername(String val)
|
|
{
|
|
this.username = val;
|
|
}
|
|
|
|
/**
|
|
* @return The username string from login dialog
|
|
*/
|
|
public String getUsername()
|
|
{
|
|
// this value may have been set by a servlet filter via a cookie
|
|
// check for this by detecting a special value in the session
|
|
FacesContext context = FacesContext.getCurrentInstance();
|
|
Map session = context.getExternalContext().getSessionMap();
|
|
|
|
String username = (String)session.get(AuthenticationHelper.SESSION_USERNAME);
|
|
if (username != null)
|
|
{
|
|
session.remove(AuthenticationHelper.SESSION_USERNAME);
|
|
this.username = username;
|
|
}
|
|
|
|
return this.username;
|
|
}
|
|
|
|
public String getUsernameInternal()
|
|
{
|
|
return this.username;
|
|
}
|
|
|
|
/**
|
|
* @param val Password from login dialog
|
|
*/
|
|
public void setPassword(String val)
|
|
{
|
|
this.password = val;
|
|
}
|
|
|
|
/**
|
|
* @return The password string from login dialog
|
|
*/
|
|
public String getPassword()
|
|
{
|
|
return this.password;
|
|
}
|
|
|
|
/**
|
|
* @return the available languages
|
|
*/
|
|
public SelectItem[] getLanguages()
|
|
{
|
|
ClientConfigElement config = (ClientConfigElement) this.configService.getGlobalConfig()
|
|
.getConfigElement(ClientConfigElement.CONFIG_ELEMENT_ID);
|
|
|
|
List<String> languages = config.getLanguages();
|
|
SelectItem[] items = new SelectItem[languages.size()];
|
|
int count = 0;
|
|
for (String locale : languages)
|
|
{
|
|
// get label associated to the locale
|
|
String label = config.getLabelForLanguage(locale);
|
|
|
|
// set default selection
|
|
if (count == 0 && this.language == null)
|
|
{
|
|
// first try to get the language that the current user is using
|
|
Locale lastLocale = Application.getLanguage(FacesContext.getCurrentInstance());
|
|
if (lastLocale != null)
|
|
{
|
|
this.language = lastLocale.toString();
|
|
}
|
|
// else we default to the first item in the list
|
|
else
|
|
{
|
|
this.language = locale;
|
|
}
|
|
}
|
|
|
|
items[count++] = new SelectItem(locale, label);
|
|
}
|
|
|
|
return items;
|
|
}
|
|
|
|
/**
|
|
* @return Returns the language selection.
|
|
*/
|
|
public String getLanguage()
|
|
{
|
|
return this.language;
|
|
}
|
|
|
|
/**
|
|
* @param language The language selection to set.
|
|
*/
|
|
public void setLanguage(String language)
|
|
{
|
|
this.language = language;
|
|
Application.setLanguage(FacesContext.getCurrentInstance(), this.language);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// Validator methods
|
|
|
|
/**
|
|
* Validate password field data is acceptable
|
|
*/
|
|
public void validatePassword(FacesContext context, UIComponent component, Object value)
|
|
throws ValidatorException
|
|
{
|
|
String pass = (String) value;
|
|
if (pass.length() < 3 || pass.length() > 32)
|
|
{
|
|
String err = MessageFormat.format(Application.getMessage(context, MSG_PASSWORD_LENGTH),
|
|
new Object[]{3, 32});
|
|
throw new ValidatorException(new FacesMessage(err));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate Username field data is acceptable
|
|
*/
|
|
public void validateUsername(FacesContext context, UIComponent component, Object value)
|
|
throws ValidatorException
|
|
{
|
|
String pass = (String) value;
|
|
if (pass.length() < 3 || pass.length() > 32)
|
|
{
|
|
String err = MessageFormat.format(Application.getMessage(context, MSG_USERNAME_LENGTH),
|
|
new Object[]{3, 32});
|
|
throw new ValidatorException(new FacesMessage(err));
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// Action event methods
|
|
|
|
/**
|
|
* Login action handler
|
|
*
|
|
* @return outcome view name
|
|
*/
|
|
public String login()
|
|
{
|
|
String outcome = null;
|
|
|
|
FacesContext fc = FacesContext.getCurrentInstance();
|
|
|
|
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
|
|
{
|
|
this.authenticationService.authenticate(this.username, this.password.toCharArray());
|
|
|
|
// setup User object and Home space ID
|
|
User user = new User(this.authenticationService.getCurrentUserName(), this.authenticationService.getCurrentTicket(),
|
|
personService.getPerson(this.username));
|
|
NodeRef homeSpaceRef = (NodeRef) this.nodeService.getProperty(personService.getPerson(this.username), ContentModel.PROP_HOMEFOLDER);
|
|
|
|
// check that the home space node exists - else user cannot login
|
|
if (this.nodeService.exists(homeSpaceRef) == false)
|
|
{
|
|
throw new InvalidNodeRefException(homeSpaceRef);
|
|
}
|
|
user.setHomeSpaceId(homeSpaceRef.getId());
|
|
|
|
// 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
|
|
String externalOutcome = (String)fc.getExternalContext().getSessionMap().get(LOGIN_OUTCOME_KEY);
|
|
if (externalOutcome != null)
|
|
{
|
|
// TODO: This is a quick solution. It would be better to specify the (identifier?)
|
|
// of a handler class that would be responsible for processing specific outcome arguments.
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("External outcome found: " + externalOutcome);
|
|
|
|
// setup is required for certain outcome requests
|
|
if (OUTCOME_DOCDETAILS.equals(externalOutcome))
|
|
{
|
|
NodeRef nodeRef = null;
|
|
|
|
String[] args = (String[]) fc.getExternalContext().getSessionMap().get(LOGIN_OUTCOME_ARGS);
|
|
if (args[0].equals(WebDAVServlet.WEBDAV_PREFIX))
|
|
{
|
|
nodeRef = resolveWebDAVPath(fc, args);
|
|
}
|
|
else if (args.length == 3)
|
|
{
|
|
StoreRef storeRef = new StoreRef(args[0], args[1]);
|
|
nodeRef = new NodeRef(storeRef, args[2]);
|
|
}
|
|
|
|
if (nodeRef != null)
|
|
{
|
|
// setup the Document on the browse bean
|
|
// TODO: the browse bean should accept a full NodeRef - not just an ID
|
|
this.browseBean.setupContentAction(nodeRef.getId(), true);
|
|
}
|
|
}
|
|
else if (OUTCOME_SPACEDETAILS.equals(externalOutcome))
|
|
{
|
|
NodeRef nodeRef = null;
|
|
|
|
String[] args = (String[]) fc.getExternalContext().getSessionMap().get(LOGIN_OUTCOME_ARGS);
|
|
if (args[0].equals(WebDAVServlet.WEBDAV_PREFIX))
|
|
{
|
|
nodeRef = resolveWebDAVPath(fc, args);
|
|
}
|
|
else if (args.length == 3)
|
|
{
|
|
StoreRef storeRef = new StoreRef(args[0], args[1]);
|
|
nodeRef = new NodeRef(storeRef, args[2]);
|
|
}
|
|
|
|
if (nodeRef != null)
|
|
{
|
|
// setup the Space on the browse bean
|
|
// TODO: the browse bean should accept a full NodeRef - not just an ID
|
|
this.browseBean.setupSpaceAction(nodeRef.getId(), true);
|
|
}
|
|
}
|
|
else if (OUTCOME_BROWSE.equals(externalOutcome))
|
|
{
|
|
String[] args = (String[]) fc.getExternalContext().getSessionMap().get(LOGIN_OUTCOME_ARGS);
|
|
if (args != null)
|
|
{
|
|
NodeRef nodeRef = null;
|
|
int offset = 0;
|
|
if (args.length >= 3)
|
|
{
|
|
offset = args.length - 3;
|
|
StoreRef storeRef = new StoreRef(args[0+offset], args[1+offset]);
|
|
nodeRef = new NodeRef(storeRef, args[2+offset]);
|
|
|
|
// setup the ref as current Id in the global navigation bean
|
|
this.navigator.setCurrentNodeId(nodeRef.getId());
|
|
|
|
// check for view mode first argument
|
|
if (args[0].equals(LOGIN_ARG_TEMPLATE))
|
|
{
|
|
this.browseBean.setDashboardView(true);
|
|
// the above call will auto-navigate to the correct outcome - so we don't!
|
|
externalOutcome = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fc.getExternalContext().getSessionMap().remove(LOGIN_OUTCOME_KEY);
|
|
return externalOutcome;
|
|
}
|
|
else
|
|
{
|
|
// if a redirect URL has been provided then use that
|
|
String redirectURL = (String)fc.getExternalContext().getSessionMap().get(LOGIN_REDIRECT_KEY);
|
|
if (redirectURL != null)
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("Redirect URL found: " + redirectURL);
|
|
|
|
// remove URL from session
|
|
fc.getExternalContext().getSessionMap().remove(LOGIN_REDIRECT_KEY);
|
|
|
|
try
|
|
{
|
|
fc.getExternalContext().redirect(redirectURL);
|
|
fc.responseComplete();
|
|
return null;
|
|
}
|
|
catch (IOException ioErr)
|
|
{
|
|
logger.warn("Unable to redirect to url: " + redirectURL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return "success";
|
|
}
|
|
}
|
|
}
|
|
catch (AuthenticationException aerr)
|
|
{
|
|
Utils.addErrorMessage(Application.getMessage(fc, MSG_ERROR_UNKNOWN_USER));
|
|
}
|
|
catch (InvalidNodeRefException refErr)
|
|
{
|
|
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(fc,
|
|
Repository.ERROR_NOHOME), refErr.getNodeRef().getId()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Utils.addErrorMessage(Application.getMessage(fc, MSG_ERROR_MISSING));
|
|
}
|
|
|
|
return outcome;
|
|
}
|
|
|
|
/**
|
|
* Invalidate ticket and logout user
|
|
*/
|
|
public String logout()
|
|
{
|
|
FacesContext context = FacesContext.getCurrentInstance();
|
|
|
|
Map session = context.getExternalContext().getSessionMap();
|
|
User user = (User) session.get(AuthenticationHelper.AUTHENTICATION_USER);
|
|
|
|
boolean alfrescoAuth = (session.get(LOGIN_EXTERNAL_AUTH) == null);
|
|
|
|
// invalidate Session for this user
|
|
if (Application.inPortalServer() == false)
|
|
{
|
|
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
|
|
request.getSession().invalidate();
|
|
}
|
|
else
|
|
{
|
|
PortletRequest request = (PortletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
|
|
request.getPortletSession().invalidate();
|
|
}
|
|
|
|
// invalidate User ticket
|
|
if (user != null)
|
|
{
|
|
this.authenticationService.invalidateTicket(user.getTicket());
|
|
}
|
|
|
|
// Request that the username cookie state is removed - this is not
|
|
// possible from JSF - so instead we setup a session variable
|
|
// which will be detected by the login.jsp/Portlet as appropriate.
|
|
session = context.getExternalContext().getSessionMap();
|
|
session.put(AuthenticationHelper.SESSION_INVALIDATED, true);
|
|
|
|
// set language to last used
|
|
if (this.language != null && this.language.length() != 0)
|
|
{
|
|
Application.setLanguage(context, this.language);
|
|
}
|
|
|
|
return alfrescoAuth ? "logout" : "relogin";
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// Private helpers
|
|
|
|
/**
|
|
* Resolves the given path elements to a NodeRef in the current repository
|
|
*
|
|
* @param context Faces context
|
|
* @param args The elements of the path to lookup
|
|
*/
|
|
private NodeRef resolveWebDAVPath(FacesContext context, String[] args)
|
|
{
|
|
NodeRef nodeRef = null;
|
|
|
|
List<String> paths = new ArrayList<String>(args.length-1);
|
|
|
|
FileInfo file = null;
|
|
try
|
|
{
|
|
// create a list of path elements (decode the URL as we go)
|
|
for (int x = 1; x < args.length; x++)
|
|
{
|
|
paths.add(URLDecoder.decode(args[x], "UTF-8"));
|
|
}
|
|
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("Attempting to resolve webdav path to NodeRef: " + paths);
|
|
|
|
// get the company home node to start the search from
|
|
NodeRef companyHome = new NodeRef(Repository.getStoreRef(),
|
|
Application.getCompanyRootId());
|
|
|
|
file = this.fileFolderService.resolveNamePath(companyHome, paths);
|
|
nodeRef = file.getNodeRef();
|
|
}
|
|
catch (UnsupportedEncodingException uee)
|
|
{
|
|
if (logger.isWarnEnabled())
|
|
logger.warn("Failed to resolve webdav path", uee);
|
|
|
|
nodeRef = null;
|
|
}
|
|
catch (FileNotFoundException fne)
|
|
{
|
|
if (logger.isWarnEnabled())
|
|
logger.debug("Failed to resolve webdav path", fne);
|
|
|
|
nodeRef = null;
|
|
}
|
|
|
|
return nodeRef;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// Private data
|
|
|
|
private static final Log logger = LogFactory.getLog(LoginBean.class);
|
|
|
|
/** I18N messages */
|
|
private static final String MSG_ERROR_MISSING = "error_login_missing";
|
|
private static final String MSG_ERROR_UNKNOWN_USER = "error_login_user";
|
|
private static final String MSG_USERNAME_CHARS = "login_err_username_chars";
|
|
private static final String MSG_USERNAME_LENGTH = "login_err_username_length";
|
|
private static final String MSG_PASSWORD_CHARS = "login_err_password_chars";
|
|
private static final String MSG_PASSWORD_LENGTH = "login_err_password_length";
|
|
|
|
public static final String LOGIN_REDIRECT_KEY = "_alfRedirect";
|
|
public static final String LOGIN_OUTCOME_KEY = "_alfOutcome";
|
|
public static final String LOGIN_OUTCOME_ARGS = "_alfOutcomeArgs";
|
|
public static final String LOGIN_EXTERNAL_AUTH= "_alfExternalAuth";
|
|
|
|
public final static String OUTCOME_DOCDETAILS = "showDocDetails";
|
|
public final static String OUTCOME_SPACEDETAILS = "showSpaceDetails";
|
|
public final static String OUTCOME_BROWSE = "browse";
|
|
|
|
private static final String LOGIN_ARG_TEMPLATE = "template";
|
|
|
|
/** user name */
|
|
private String username = null;
|
|
|
|
/** password */
|
|
private String password = null;
|
|
|
|
/** language locale selection */
|
|
private String language = null;
|
|
|
|
/** PersonService bean reference */
|
|
private PersonService personService;
|
|
|
|
/** AuthenticationService bean reference */
|
|
private AuthenticationService authenticationService;
|
|
|
|
/** NodeService bean reference */
|
|
private NodeService nodeService;
|
|
|
|
/** The BrowseBean reference */
|
|
private BrowseBean browseBean;
|
|
|
|
/** The NavigationBean bean reference */
|
|
private NavigationBean navigator;
|
|
|
|
/** ConfigService bean reference */
|
|
private ConfigService configService;
|
|
|
|
/** FileFolderService bean reference */
|
|
private FileFolderService fileFolderService;
|
|
}
|