mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
20954: Calendar Dashlet updates. Fixes: ALF-2907 (meeting workspace issue) 20968: Minor VersionableAspect fix to onDeleteNode policy firing (follow-on for r19507) 20981: Removed Install Jammer installers from V3.3.3 20982: AVMTestSuite - run PurgeTestP after AVMServiceTest (investigating ALF-3611) 20997: Fix for ALF-2605 - updated share-config-custom.xml.sample and removed obsolete extension files 21030: Pulled XAMConnector AMP into main 3.3SP3 codeline. Apart from build changes (incl. EOL), there are no repo changes. 21032: StoreSelector passes through NodeContentContext allowing stores access to node information 21036: Fix ALF-245: Can't delete space that contains "translation without content" - Delete triggers 'unmakeTranslation' - Empty translations are marked with sys:temporary before being deleted 21051: More on fix ALF-245. Reduced complexity by not deleting empty translations twice 21064: Merged V3.3 to V3.3-BUG_FIX 20898: Merged HEAD to V3.3 20724: AVMTestSuite - temporarily comment out PurgeTestP - TODO: investigate intermittent test failure 20903: Incremented version revision 20921: AVM - fix purge store so that vr nodes are actually orphaned (ALF-3627) 20952: Fix for ALF-3704: Module conflict - Alfresco web client config property page missing metadata. This is application of a fix made to the config service in a hotfix. The change provides a deterministic load order for config files loaded via the ConfigBootstrap spring bean. More importantly it means that config files loaded by modules on different machines in a cluster load in the same order. The forms client and AWE config files have been updated to take advantage of the new loading order. 21061: Merged PATCHES/V3.1.2 to V3.3 (RECORD ONLY) 20890: ALF-3687: Apply LUCENE-1383 patch to Lucene 2.1.0 to reduce memory leaks from ThreadLocals 20891: ALF-3687: Build classpath fix 20892: Incremented version label 21062: Merged PATCHES/V3.2.1 to V3.3 20897: (RECORD ONLY) Incremented version label 20901: (RECORD ONLY) ALF-3740: Merged V3.3 to PATCHES/V3.2.1 20524: VersionMigrator - option to run as scheduled job (ALF-1000) 20904: (RECORD ONLY) ALF-3732: Merged PATCHES/V3.2.r to PATCHES/V3.2.1 19803: ALF-558: File servers (CIFS / FTP / NFS) can now handle concurrent write operations on Alfresco repository - ContentDiskDriver / AVMDiskDriver now use retrying transactions for write operations - Disable EagerContentStoreCleaner on ContentDiskDriver / AVMDiskDriver closeFile() operations so that they may be retried after rollback (Sony zero byte problem) - Allow manual association of AVM ContentData with nodes so that closeFile() may be retried - Propagation of new argument through AVM interfaces 20905: (RECORD ONLY) ALF-3732: Rolled back the now unnecessary reference()/dereference() stuff from ALF-558 20906: (RECORD ONLY) ALF-3732: Merged DEV/V3.3-BUG-FIX to PATCHES/V3.2.1 20623: Fix for ALF-3188 : Access Denied when updating doc via CIFS 20907: (RECORD ONLY) ALF-3732: Merged V3.3 to PATCHES/V3.2.1 20173: Propagate IOExceptions from retryable write transactions in AlfrescoDiskDriver 20950: ALF-3779: Upgrades on large repositories from v2.1 and v2.2 were failing on MySQL due to "The total number of locks exceeds the lock table size" errors - Solution was to add support for new --BEGIN TXN and --END TXN comments and execute LOCK TABLES statements in the same transaction as large INSERT - SELECT statements. 20990: ALF-3789: Concurrency issues with InMemoryTicketComponentImpl - Previous ETHREEOH-1842 method of caching web session 'ref counts' against tickets could cause tickets to unpredictably fall out of the transactional cache - Rolled back original ETHREEOH-1842 fix. Would be too much overhead to keep these ref counts consistent across a cluster. - Instead, avoid invalidating tickets on web session timeout and only do it on explicit log out. - Now tickets maintained in non-transactional shared cache so they can't drop out unpredictably - Logic for ticket inactivity timeout caching improved so that it should work across a cluster 20991: (RECORD ONLY) Incremented version label 20993: ALF-3789: Fixed Spring configuration backward compatibily issue with previous fix - Ticket cache bean name restored to ticketsCache. This is actually now a non-transactional cache. - Also externalized parameters so that they can now be controlled by alfresco-global.properties without any bean overrides authentication.ticket.ticketsExpire=false authentication.ticket.expiryMode=AFTER_FIXED_TIME authentication.ticket.validDuration=PT1H 20994: Eclipse classpath fixes for unit testing after ant build 21057: ALF-3592: PassthruCifsAuthenticator now auto-creates / imports users who do not already exist in Alfresco - At least one of the following properties must be true for this to happen synchronization.autoCreatePeopleOnLogin synchronization.syncWhenMissingPeopleLogIn - Also improved debug logging of unknown passthru domains 21063: Merged PATCHES/V3.2.r to V3.3 21037: ALF-3793: Final attempt at realigning saved XForm data with a modified Schema - removeRemovedNodes / insertUpdatedNodes / insertPrototypeNodes replaced by a one stop recursive process that builds a new instance tree from scratch - Nodes copied over in correct order - Missing nodes added in and extra nodes discarded - Prototype nodes appended at appropriate points 21038: (RECORD ONLY) Incremented version label git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@21065 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
461 lines
16 KiB
Java
461 lines
16 KiB
Java
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package org.alfresco.web.bean;
|
|
|
|
import java.io.IOException;
|
|
import java.io.Serializable;
|
|
import java.text.MessageFormat;
|
|
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.validator.ValidatorException;
|
|
|
|
import org.alfresco.model.ContentModel;
|
|
import org.alfresco.repo.security.authentication.AuthenticationDisallowedException;
|
|
import org.alfresco.repo.security.authentication.AuthenticationException;
|
|
import org.alfresco.repo.security.authentication.AuthenticationMaxUsersException;
|
|
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.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.bean.users.UserPreferencesBean;
|
|
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 implements Serializable
|
|
{
|
|
/**
|
|
* The default outcome of the logout action.
|
|
*/
|
|
private static final String OUTCOME_LOGOUT = "logout";
|
|
|
|
/**
|
|
* The outcome of the logout action when the user has been signed on by SSO.
|
|
*/
|
|
private static final String OUTCOME_RELOGIN = "relogin";
|
|
|
|
/**
|
|
* The name of the form parameter carrying the outcome to the logout action.
|
|
*/
|
|
private static final String PARAM_OUTCOME = "outcome";
|
|
|
|
private static final long serialVersionUID = 7417882503323795282L;
|
|
|
|
/**
|
|
* @param authenticationService The AuthenticationService to set.
|
|
*/
|
|
public void setAuthenticationService(AuthenticationService authenticationService)
|
|
{
|
|
this.authenticationService = authenticationService;
|
|
}
|
|
|
|
protected AuthenticationService getAuthenticationService()
|
|
{
|
|
if (authenticationService == null)
|
|
authenticationService = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getAuthenticationService();
|
|
return authenticationService;
|
|
}
|
|
|
|
/**
|
|
* @param personService The personService to set.
|
|
*/
|
|
public void setPersonService(PersonService personService)
|
|
{
|
|
this.personService = personService;
|
|
}
|
|
|
|
protected PersonService getPersonService()
|
|
{
|
|
if (personService == null)
|
|
personService = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getPersonService();
|
|
return personService;
|
|
}
|
|
|
|
/**
|
|
* @param nodeService The nodeService to set.
|
|
*/
|
|
public void setNodeService(NodeService nodeService)
|
|
{
|
|
this.nodeService = nodeService;
|
|
}
|
|
|
|
protected NodeService getNodeService()
|
|
{
|
|
if (nodeService == null)
|
|
nodeService = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getNodeService();
|
|
return 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 preferences The UserPreferencesBean to set
|
|
*/
|
|
public void setUserPreferencesBean(UserPreferencesBean preferences)
|
|
{
|
|
this.preferences = preferences;
|
|
}
|
|
|
|
public UserPreferencesBean getUserPreferencesBean()
|
|
{
|
|
return preferences;
|
|
}
|
|
|
|
/**
|
|
* @return "logout" if the default Alfresco authentication process is being used, else "relogin"
|
|
* if an external authorisation mechanism is present.
|
|
*/
|
|
public String getLogoutOutcome()
|
|
{
|
|
Map<?, ?> session = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
|
|
return session.get(LOGIN_EXTERNAL_AUTH) == null ? OUTCOME_LOGOUT : OUTCOME_RELOGIN;
|
|
}
|
|
|
|
/**
|
|
* @param val Username from login dialog
|
|
*/
|
|
public void setUsername(String val)
|
|
{
|
|
if ( val != null ) { val = val.trim(); }
|
|
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 true to display language selection, false to
|
|
*/
|
|
public boolean isLanguageSelect()
|
|
{
|
|
return Application.getClientConfig(FacesContext.getCurrentInstance()).isLanguageSelect();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// Validator methods
|
|
|
|
/**
|
|
* Validate password field data is acceptable
|
|
*/
|
|
public void validatePassword(FacesContext context, UIComponent component, Object value)
|
|
throws ValidatorException
|
|
{
|
|
int minPasswordLength = Application.getClientConfig(context).getMinPasswordLength();
|
|
|
|
String pass = (String)value;
|
|
if (pass.length() < minPasswordLength || pass.length() > 256)
|
|
{
|
|
String err = MessageFormat.format(Application.getMessage(context, MSG_PASSWORD_LENGTH),
|
|
new Object[]{minPasswordLength, 256});
|
|
throw new ValidatorException(new FacesMessage(err));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate Username field data is acceptable
|
|
*/
|
|
public void validateUsername(FacesContext context, UIComponent component, Object value)
|
|
throws ValidatorException
|
|
{
|
|
int minUsernameLength = Application.getClientConfig(context).getMinUsernameLength();
|
|
|
|
String name = ((String)value).trim();
|
|
|
|
if (name.length() < minUsernameLength || name.length() > 256)
|
|
{
|
|
String err = MessageFormat.format(Application.getMessage(context, MSG_USERNAME_LENGTH),
|
|
new Object[]{minUsernameLength, 256});
|
|
throw new ValidatorException(new FacesMessage(err));
|
|
}
|
|
if (name.indexOf('"') != -1)
|
|
{
|
|
String err = MessageFormat.format(Application.getMessage(context, MSG_USER_ERR),
|
|
new Object[]{"\""});
|
|
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.username.length() != 0 &&
|
|
this.password != null && this.password.length() != 0)
|
|
{
|
|
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.getAuthenticationService().authenticate(this.username, this.password.toCharArray());
|
|
|
|
// Set the user name as stored by the back end
|
|
this.username = this.getAuthenticationService().getCurrentUserName();
|
|
|
|
// 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.username,
|
|
this.getAuthenticationService().getCurrentTicket(),
|
|
getPersonService().getPerson(this.username));
|
|
|
|
NodeRef homeSpaceRef = (NodeRef) this.getNodeService().getProperty(getPersonService().getPerson(this.username), ContentModel.PROP_HOMEFOLDER);
|
|
|
|
// check that the home space node exists - else user cannot login
|
|
if (homeSpaceRef == null || this.getNodeService().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
|
|
Application.setCurrentUser(fc, user);
|
|
|
|
// Programatically retrieve the LoginOutcomeBean from JSF
|
|
LoginOutcomeBean loginOutcomeBean = (LoginOutcomeBean) fc.getApplication().createValueBinding(
|
|
"#{LoginOutcomeBean}").getValue(fc);
|
|
|
|
// 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
|
|
String redirectURL = loginOutcomeBean.getRedirectURL();
|
|
if (redirectURL != null && redirectURL.length() > 0)
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
logger.debug("Redirect URL found: " + redirectURL);
|
|
|
|
try
|
|
{
|
|
fc.getExternalContext().redirect(redirectURL);
|
|
fc.responseComplete();
|
|
return null;
|
|
}
|
|
catch (IOException ioErr)
|
|
{
|
|
logger.warn("Unable to redirect to url: " + redirectURL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// special case to handle jump to My Alfresco page initially
|
|
|
|
// note: to enable MT runtime client config customization, need to re-init NavigationBean
|
|
// in context of tenant login page
|
|
this.navigator.initFromClientConfig();
|
|
|
|
if (NavigationBean.LOCATION_MYALFRESCO.equals(this.preferences.getStartLocation()))
|
|
{
|
|
return "myalfresco";
|
|
}
|
|
else
|
|
{
|
|
// generally this will navigate to the generic browse screen
|
|
return "success";
|
|
}
|
|
}
|
|
}
|
|
catch (AuthenticationDisallowedException aerr)
|
|
{
|
|
Utils.addErrorMessage(Application.getMessage(fc, MSG_ERROR_LOGIN_DISALLOWED));
|
|
}
|
|
catch (AuthenticationMaxUsersException aerr)
|
|
{
|
|
Utils.addErrorMessage(Application.getMessage(fc, MSG_ERROR_LOGIN_MAXUSERS));
|
|
}
|
|
catch (AuthenticationException aerr)
|
|
{
|
|
Utils.addErrorMessage(Application.getMessage(fc, MSG_ERROR_UNKNOWN_USER));
|
|
}
|
|
catch (InvalidNodeRefException refErr)
|
|
{
|
|
String msg;
|
|
if (refErr.getNodeRef() != null)
|
|
{
|
|
msg = refErr.getNodeRef().toString();
|
|
}
|
|
else
|
|
{
|
|
msg = Application.getMessage(fc, MSG_NONE);
|
|
}
|
|
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(fc,
|
|
Repository.ERROR_NOHOME), msg));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Utils.addErrorMessage(Application.getMessage(fc, MSG_ERROR_MISSING));
|
|
}
|
|
|
|
return outcome;
|
|
}
|
|
|
|
/**
|
|
* Invalidate ticket and logout user
|
|
*/
|
|
public String logout()
|
|
{
|
|
FacesContext context = FacesContext.getCurrentInstance();
|
|
|
|
// The outcome is decided in advance (before session expiry) and included as a parameter
|
|
Map<?, ?> params = context.getExternalContext().getRequestParameterMap();
|
|
String outcome = (String)params.get(PARAM_OUTCOME);
|
|
if (outcome == null)
|
|
{
|
|
outcome = OUTCOME_LOGOUT;
|
|
}
|
|
|
|
Locale language = Application.getLanguage(context);
|
|
|
|
// Perform log out actions
|
|
Application.logOut(context);
|
|
|
|
// set language to last used on the login page
|
|
Application.setLanguage(context, language.toString());
|
|
|
|
return outcome;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// 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_ERROR_LOGIN_DISALLOWED = "error_login_disallowed";
|
|
private static final String MSG_ERROR_LOGIN_MAXUSERS = "error_login_maxusers";
|
|
private static final String MSG_NONE = "none";
|
|
|
|
public static final String MSG_ERROR_LOGIN_NOPERMISSIONS = "login_err_permissions";
|
|
public static final String MSG_USERNAME_LENGTH = "login_err_username_length";
|
|
public static final String MSG_PASSWORD_LENGTH = "login_err_password_length";
|
|
public static final String MSG_USER_ERR = "user_err_user_name";
|
|
|
|
public static final String LOGIN_EXTERNAL_AUTH = "_alfExternalAuth";
|
|
public static final String LOGIN_NOPERMISSIONS = "_alfNoPermissions";
|
|
|
|
/** user name */
|
|
private String username = null;
|
|
|
|
/** password */
|
|
private String password = null;
|
|
|
|
/** PersonService bean reference */
|
|
private transient PersonService personService;
|
|
|
|
/** AuthenticationService bean reference */
|
|
private transient AuthenticationService authenticationService;
|
|
|
|
/** NodeService bean reference */
|
|
private transient NodeService nodeService;
|
|
|
|
/** The BrowseBean reference */
|
|
protected BrowseBean browseBean;
|
|
|
|
/** The NavigationBean bean reference */
|
|
protected NavigationBean navigator;
|
|
|
|
/** The user preferences bean reference */
|
|
protected UserPreferencesBean preferences;
|
|
} |