/*
* Copyright (C) 2008-2012 Open Wide SA
*
* This program is FREE software. You can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your opinion) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, write to the Free Software Foundation,
* Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* More information at http://knowledge.openwide.fr/bin/view/Main/AlfrescoETLConnector/
*
*/
package fr.openwide.talendalfresco.rest.server.command;
import javax.servlet.http.HttpSession;
import javax.transaction.UserTransaction;
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.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.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.I18NUtil;
import fr.openwide.talendalfresco.rest.RestConstants;
import fr.openwide.talendalfresco.rest.server.RestServerHelper;
import fr.openwide.talendalfresco.rest.server.processor.RestCommandBase;
import fr.openwide.talendalfresco.rest.server.processor.RestCommandResult;
/**
* Login command
*
* @author Marc Dutoo - Open Wide SA
*
*/
public class LoginCommand extends RestCommandBase {
// static logger
private static Log logger = LogFactory.getLog(LoginCommand.class);
private static final String[] PROPERTIES = new String[] {
RestConstants.PROP_LOGIN_USERNAME, RestConstants.PROP_LOGIN_PASSWORD, RestConstants.PROP_LOGIN_TICKET };
public String[] getPropertyNames() {
return PROPERTIES;
}
public LoginCommand() {
super(RestConstants.CMD_LOGIN);
}
/**
*
* @return
*/
protected boolean validateArgumentsImpl() {
try {
RestServerHelper.validateUsername(null, args.get(RestConstants.PROP_LOGIN_USERNAME));
RestServerHelper.validatePassword(null, args.get(RestConstants.PROP_LOGIN_PASSWORD));
return true;
} catch (Exception ex) { // RestRuntimeException
String msg = "Bad parameters for command "
+ getCommandName() + " which requires" + getPropertyNames()
+ "but got " + args + " : " + ex.getMessage();
xmlResult.setError(RestCommandResult.CODE_ERROR_WRONG_PARAMETERS, msg, ex);
logger.error(msg);
return false;
}
}
public void executeImpl() {
String username = args.get(RestConstants.PROP_LOGIN_USERNAME);
String password = args.get(RestConstants.PROP_LOGIN_PASSWORD);
String ticket = args.get(RestConstants.PROP_LOGIN_TICKET);
try {
User user = this.authenticate(username, password, ticket);
if (user == null) {
// error whose message has been written in xmlResult
return;
}
xmlResult.writeTag("jsessionid", httpRequest.getSession(true).getId());
xmlResult.writeTag("ticket", user.getTicket());
xmlResult.writeTag("personNodeRef", user.getPerson().toString());
xmlResult.writeTag("homeNodeRef", "workspace://SpacesStore/" + user.getHomeSpaceId());
xmlResult.writeTag("login", user.getUserName());
xmlResult.writeTag("relativelServerUrlPrefix", httpRequest.getContextPath());
xmlResult.writeTag("fullServerUrlPrefix", httpRequest.getScheme()
+ "://" + httpRequest.getServerName() + ":" + httpRequest.getServerPort()
+ httpRequest.getContextPath());
//xmlResult.setMessage("Successfully authenticated"); // opt
} catch (Exception ex) {
// error while logging in or writing alfresco node XML
String msg = "Error while authenticating " + username;
logger.error(msg, ex);
xmlResult.setError(RestConstants.CODE_ERROR_AUTH, msg, ex);
}
}
private User authenticate(String username, String password, String ticket) {
// case of existing session user : getting alfresco ticket
User existingSessionUser = null;
HttpSession session = httpRequest.getSession(false);
if (session != null) {
existingSessionUser = (User)session.getAttribute(AuthenticationHelper.AUTHENTICATION_USER);
if (existingSessionUser != null) {
String existingSessionTicket = existingSessionUser.getTicket();
// alternatives :
// 1. using alfresco ticket rather than sso ticket to speed up things
// NB. this means that before logging in a different user an explicit logout must be done
// 2. using sso ticket rather than alfresco one
// this requires never to give the ticket but when we want to relog, which is bothersome
if (existingSessionTicket != null) {
ticket = existingSessionTicket;
}
}
}
UserTransaction tx = null;
try {
// 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
if (username != null && password != null) {
// authentication using login (alfresco or sso), since user/pwd params (even empty ones) have been supplied
// validation :
RestServerHelper.validateUsername(session, username);
RestServerHelper.validatePassword(session, password);
// login :
authenticationService.authenticate(username, password.toCharArray());
} else if (ticket != null && ticket.length() != 0) {
// authentication using ticket (alfresco or sso), since non empty ticket has been supplied
authenticationService.validate(ticket);
} else {
xmlResult.setError(RestCommandResult.CODE_ERROR_AUTH_MISSING,
RestServerHelper.getMessage(session, RestServerHelper.MSG_ERROR_MISSING)
+ " : " + username, null);
return null;
}
// Set the user name as stored by the back end
username = authenticationService.getCurrentUserName();
if (existingSessionUser != null && existingSessionUser.getUserName().equals(username)) {
// user was already logged in, nothing else to do
return existingSessionUser;
}
// now setting up logged in user elements
// using non propagated tx because already inside a tx (commandServlet)
tx = transactionService.getNonPropagatingUserTransaction();
tx.begin();
// remove the session invalidated flag (used to remove last username cookie by AuthenticationFilter)
if (session != null) {
session.removeAttribute(AuthenticationHelper.SESSION_INVALIDATED);
}
// setup User object and Home space ID
User user = new User(username,
authenticationService.getCurrentTicket(),
personService.getPerson(username));
NodeRef homeSpaceRef = (NodeRef) nodeService.getProperty(personService.getPerson(username),
ContentModel.PROP_HOMEFOLDER);
// check that the home space node exists - else user cannot login
if (nodeService.exists(homeSpaceRef) == false) {
throw new InvalidNodeRefException(homeSpaceRef);
}
user.setHomeSpaceId(homeSpaceRef.getId());
tx.commit();
tx = null; // clear this so we know not to rollback
// put the User object in the Session - the authentication servlet will then allow
// the app to continue without redirecting to the login page
if (session == null) {
session = httpRequest.getSession(true); // creating session if none yet
}
session.setAttribute(AuthenticationHelper.AUTHENTICATION_USER, user);
// Set the current locale for Alfresco web app. NB. session exists now.
I18NUtil.setLocale(Application.getLanguage(session, true));
return user;
} catch (AuthenticationException ae) {
xmlResult.setError(RestCommandResult.CODE_ERROR_AUTH_UNKNOWN_USER,
RestServerHelper.getMessage(session, RestServerHelper.MSG_ERROR_UNKNOWN_USER)
+ " : " + username, ae);
} catch (InvalidNodeRefException inre) {
xmlResult.setError(RestCommandResult.CODE_ERROR_AUTH_UNKNOWN_USER,
RestServerHelper.getMessage(session, Repository.ERROR_NOHOME)
+ " : " + inre.getNodeRef().getId() + " (" + username + ")", inre);
} catch (Throwable e) {
// Some other kind of serious failure
xmlResult.setError("Unknown technical error when authenticating user "
+ username, null);
} finally {
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
return null;
}
}