/*
*
* Copyright 2013 Entando S.r.l. (http://www.entando.com) All rights reserved.
*
* This file is part of Entando software.
* Entando is a free software;
* You can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) as published by the Free Software Foundation; version 2.
*
* See the file License for the specific language governing permissions
* and limitations under the License
*
*
*
* Copyright 2013 Entando S.r.l. (http://www.entando.com) All rights reserved.
*
*/
package com.agiletec.plugins.jpuserreg.aps.system.services.userreg;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.Map.Entry;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import com.agiletec.aps.system.ApsSystemUtils;
import com.agiletec.aps.system.SystemConstants;
import com.agiletec.aps.system.common.AbstractService;
import com.agiletec.aps.system.common.entity.IEntityManager;
import com.agiletec.aps.system.common.entity.model.EntitySearchFilter;
import com.agiletec.aps.system.common.entity.model.IApsEntity;
import com.agiletec.aps.system.common.entity.model.attribute.AttributeInterface;
import com.agiletec.aps.system.common.entity.model.attribute.MonoTextAttribute;
import com.agiletec.aps.system.common.entity.model.attribute.TextAttribute;
import com.agiletec.aps.system.exception.ApsSystemException;
import com.agiletec.aps.system.services.authorization.authorizator.IApsAuthorityManager;
import com.agiletec.aps.system.services.baseconfig.ConfigInterface;
import com.agiletec.aps.system.services.group.Group;
import com.agiletec.aps.system.services.group.IGroupManager;
import com.agiletec.aps.system.services.lang.ILangManager;
import com.agiletec.aps.system.services.lang.Lang;
import com.agiletec.aps.system.services.page.IPage;
import com.agiletec.aps.system.services.page.IPageManager;
import com.agiletec.aps.system.services.role.IRoleManager;
import com.agiletec.aps.system.services.role.Role;
import com.agiletec.aps.system.services.url.IURLManager;
import com.agiletec.aps.system.services.user.IUserManager;
import com.agiletec.aps.system.services.user.User;
import com.agiletec.aps.system.services.user.UserDetails;
import com.agiletec.aps.util.DateConverter;
import com.agiletec.plugins.jpmail.aps.services.mail.IMailManager;
import com.agiletec.plugins.jpuserreg.aps.JpUserRegSystemConstants;
import com.agiletec.plugins.jpuserreg.aps.system.services.userreg.model.IUserRegConfig;
import com.agiletec.plugins.jpuserreg.aps.system.services.userreg.model.Template;
import com.agiletec.plugins.jpuserreg.aps.system.services.userreg.parse.UserRegConfigDOM;
import com.agiletec.plugins.jpuserreg.aps.system.services.userreg.util.ShaEncoder;
import org.entando.entando.aps.system.services.userprofile.IUserProfileManager;
import org.entando.entando.aps.system.services.userprofile.model.IUserProfile;
/**
* Manager for operations of user account registration.
* @author S.Puddu
* @author E.Mezzano
* @author G.Cocco
*/
@Aspect
public class UserRegManager extends AbstractService implements IUserRegManager {
@Override
public void init() throws Exception {
this.loadConfigs();
ApsSystemUtils.getLogger().debug(this.getClass().getName() + ": initialized");
}
private void loadConfigs() throws ApsSystemException {
try {
ConfigInterface configManager = this.getConfigManager();
String xml = configManager.getConfigItem(JpUserRegSystemConstants.USER_REG_CONFIG_ITEM);
if (xml == null) {
throw new ApsSystemException("Configuration Item not found: " + JpUserRegSystemConstants.USER_REG_CONFIG_ITEM);
}
UserRegConfigDOM userRegConfigDom = new UserRegConfigDOM();
IUserRegConfig config = userRegConfigDom.extractConfig(xml);
this.setUserRegConfig(config);
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "loadConfigs");
throw new ApsSystemException("Error in init", t);
}
}
@Override
public IUserRegConfig getUserRegConfig() {
return this.getConfig().clone();
}
@Override
public void saveUserRegConfig(IUserRegConfig config) throws ApsSystemException {
try {
String xml = new UserRegConfigDOM().createConfigXml(config);
this.getConfigManager().updateConfigItem(JpUserRegSystemConstants.USER_REG_CONFIG_ITEM, xml);
this.setUserRegConfig(config);
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "saveUserRegConfig");
throw new ApsSystemException("Errore in fase di aggiornamento configurazione user reg", t);
}
}
protected IUserRegConfig getConfig() {
return _userRegConfig;
}
protected void setUserRegConfig(IUserRegConfig regProfileConfig) {
this._userRegConfig = regProfileConfig;
this.setTokenValidityInMillis(regProfileConfig.getTokenValidityMinutes()*60000L);
}
@AfterReturning(
pointcut="execution(* com.agiletec.aps.system.services.user.IUserManager.removeUser(..)) && args(key)")
public void deleteUser(Object key) {
String username = null;
if (key instanceof String) {
username = key.toString();
} else if (key instanceof UserDetails) {
UserDetails userDetails = (UserDetails) key;
username = userDetails.getUsername();
}
if (username != null) {
try {
this.getUserRegDAO().clearTokenByUsername(username);
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "deleteUser", "Error removing username " + username);
}
}
}
@Override
public void regAccount(IUserProfile userProfile) throws ApsSystemException {
try {
User user = new User();
user.setDisabled(true);
user.setUsername(userProfile.getUsername());
user.setProfile(userProfile);
user.setPassword("");
String token = this.createToken(userProfile.getUsername());
this.sendAlertRegProfile((IUserProfile) user.getProfile(), token);
this.getUserManager().addUser(user);
this.getUserRegDAO().addActivationToken(userProfile.getUsername(), token, new Date(), IUserRegDAO.ACTIVATION_TOKEN_TYPE);
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "regAccount");
throw new ApsSystemException("Error in Account registration", t);
}
}
@Override
public void reactivationByEmail(String email) throws ApsSystemException {
try {
Collection<String> usernames = this.getUsernamesByEmail(email);
Iterator<String> usernamesIter = usernames.iterator();
while (usernamesIter.hasNext()) {
String userName = (String) usernamesIter.next();
this.reactivationByUserName(userName);
}
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "reactivationByEmail");
throw new ApsSystemException("Error in request for Account Reactivation", t);
}
}
@Override
public void activateUser(String username, String password, String token) throws ApsSystemException {
try {
IUserManager userManager = this.getUserManager();
this.clearOldAccountRequests();
User user = (User) userManager.getUser(username);
user.setLastPasswordChange(new Date());
user.setPassword(password);
user.setDisabled(false);
this.loadUserDefaultRoles(user);
this.loadUserDefaultGroups(user);
userManager.updateUser(user);
userManager.changePassword(username, password);// Per salvare password non in chiaro
this.getUserRegDAO().removeConsumedToken(token);
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "activateUser");
throw new ApsSystemException("Error in Account activation", t);
}
}
@Override
public void reactivateUser(String username, String password, String token) throws ApsSystemException {
try {
IUserManager userManager = this.getUserManager();
this.clearOldAccountRequests();
User user = (User) userManager.getUser(username);
user.setLastPasswordChange(new Date());
user.setPassword(password);
user.setDisabled(false);
userManager.updateUser(user);
userManager.changePassword(username, password);// Per salvare password non in chiaro
this.getUserRegDAO().removeConsumedToken(token);
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "reactivateUser");
throw new ApsSystemException("Error in Account activation", t);
}
}
@Override
public void clearOldAccountRequests() throws ApsSystemException {
long time = new Date().getTime()-this.getTokenValidityInMillis();
Date expiration = new Date(time);
this.getUserRegDAO().clearOldTokens(expiration);
List<String> usernames = this.getUserRegDAO().oldAccountsNotActivated(expiration);
//Ragionarci
Iterator<String> it = usernames.iterator();
while (it.hasNext()) {
String current = (String) it.next();
this.getUserManager().removeUser(current);
this.getUserRegDAO().clearTokenByUsername(current);
}
}
@Override
public void deactivateUser(UserDetails user) throws ApsSystemException {
try {
if (user instanceof User) {
((User)user).setDisabled(true);
this.getUserManager().updateUser(user);
}
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "deactivateUser");
throw new ApsSystemException("Error in Account deactivation", t);
}
}
@Override
public String getUsernameFromToken(String token){
return this.getUserRegDAO().getUsernameFromToken(token);
}
@Override
public Collection<String> getUsernamesByEmail(String email) throws ApsSystemException {
try {
Collection<String> usernames = new HashSet<String>();
IUserProfileManager profileManager = this.getUserProfileManager();
Iterator<IApsEntity> prototypes = profileManager.getEntityPrototypes().values().iterator();
while (prototypes.hasNext()) {
IApsEntity prototype = prototypes.next();
AttributeInterface eMailAttr = prototype.getAttributeByRole(SystemConstants.USER_PROFILE_ATTRIBUTE_ROLE_MAIL);
if (eMailAttr!=null) {
EntitySearchFilter[] filters = {
new EntitySearchFilter(IEntityManager.ENTITY_TYPE_CODE_FILTER_KEY, false, prototype.getTypeCode(), false),
new EntitySearchFilter(eMailAttr.getName(), true, email, false) };
usernames.addAll(profileManager.searchId(filters));
}
}
return usernames;
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "getUsernamesFromEmail");
throw new ApsSystemException("Error searching users with email " + email, t);
}
}
@Override
public void reactivationByUserName(String username) throws ApsSystemException {
try {
IUserProfile profile = this.getUserProfileManager().getProfile(username);
if (null != profile) {
String token = this.createToken(username);
this.getUserRegDAO().clearTokenByUsername(username);
this.getUserRegDAO().addActivationToken(username, token, new Date(), IUserRegDAO.REACTIVATION_RECOVER_TOKEN_TYPE);
this.sendAlertReactivateUser(username, profile, token);
}
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "reactivationByUserName");
throw new ApsSystemException("Error in request for Account Reactivation", t);
}
}
/**
* Create link for email confirmation
*/
protected String createLink(String pageCode, String userName, String token, String langcode) {
Map<String, String> params = new HashMap<String, String>();
params.put("token", token);
Lang lang = this.getLangManager().getLang(langcode);
IPage page = this.getPageManager().getPage(pageCode);
if (null == page) {
page = this.getPageManager().getRoot();
}
return this.getUrlManager().createUrl(page, lang, params);
}
/**
* Populate email template
* */
protected String replaceParams(String defaultText, Map<String, String> params) {
String body = defaultText;
StringBuffer strBuff = null;
Iterator<Entry<String, String>> it = params.entrySet().iterator();
while (it.hasNext()) {
Entry<String, String> pairs = it.next();
String field = "{" + pairs.getKey() + "}";
int start = body.indexOf(field);
if (start > 0) {
int end = start + field.length();
strBuff = new StringBuffer();
strBuff.append(body.substring(0, start));
strBuff.append(pairs.getValue());
strBuff.append(body.substring(end));
body = strBuff.toString();
}
}
return body;
}
/**
* Generated random token
* */
protected String createToken(String userName) throws NoSuchAlgorithmException {
Random random = new Random();
StringBuffer salt = new StringBuffer();
long rndLong = random.nextLong();
salt.append(rndLong);
String date = DateConverter.getFormattedDate(new Date(), "SSSmmyyyy-SSS-MM:ssddmmHHmmEEE");
salt.append(date);
rndLong = random.nextLong();
salt.append(rndLong);
// genero il token in base a username e salt
String token = ShaEncoder.encodePassword(userName, salt.toString());
return token;
}
/**
* Prepares the parameters to populate email's template
*/
private Map<String, String> prepareMailParams(IUserProfile profile, String token, String pageCode) {
Map<String, String> params = new HashMap<String, String>();
/*
String name = this.getFieldValue(profile, SystemConstants.ATTRIBUTE_ROLE_FIRST_NAME);
params.put("name", name!=null ? name : "");
String surname = this.getFieldValue(profile, ProfileSystemConstants.ATTRIBUTE_ROLE_SURNAME);
params.put("surname", surname!=null ? surname : "");
*/
String fullname = this.getFieldValue(profile, SystemConstants.USER_PROFILE_ATTRIBUTE_ROLE_FULL_NAME);
params.put("fullname", fullname!=null ? fullname : "");
String username = profile.getUsername();
params.put("userName", username);
String profileLangAttr = this.getLangForLinkCreation(profile);
String link = this.createLink(pageCode, username, token, profileLangAttr);
params.put("link", link);
return params;
}
private String getLangForLinkCreation(IUserProfile profile) {
ILangManager langManager = this.getLangManager();
String langCode = this.getFieldValue(profile, JpUserRegSystemConstants.ATTRIBUTE_ROLE_LANGUAGE);
if (null == langCode || langCode.length() == 0 || langManager.getLang(langCode)==null) {
langCode = langManager.getDefaultLang().getCode();
}
return langCode;
}
private String getFieldValue(IApsEntity entity, String roleName) {
String value = null;
AttributeInterface attribute = entity.getAttributeByRole(roleName);
if (attribute!=null) {
if (attribute instanceof MonoTextAttribute) {
value = ((MonoTextAttribute) attribute).getText();
} else if (attribute instanceof TextAttribute) {
value = ((TextAttribute) attribute).getTextForLang(this.getLangManager().getDefaultLang().getCode());
}
}
return value;
}
private void sendAlertRegProfile(IUserProfile profile, String token) throws ApsSystemException {
IUserRegConfig config = this.getConfig();
String activationPageCode = config.getActivationPageCode();
Map<String, String> params = this.prepareMailParams(profile, token, activationPageCode);
this.sendAlert(config.getActivationTemplates(), params, profile);
}
private void sendAlertReactivateUser(String userName, IUserProfile profile, String token) throws ApsSystemException {
IUserRegConfig config = this.getConfig();
String reactivationPageCode = config.getReactivationPageCode();
Map<String, String> params = this.prepareMailParams(profile, token, reactivationPageCode);
this.sendAlert(config.getReactivationTemplates(), params, profile);
}
private void sendAlert(Map<String, Template> templates, Map<String, String> params, IUserProfile profile) throws ApsSystemException {
IUserRegConfig config = this.getConfig();
String[] eMail = { this.getFieldValue(profile, SystemConstants.USER_PROFILE_ATTRIBUTE_ROLE_MAIL) };
Template template = null;
String langCode = this.getFieldValue(profile, JpUserRegSystemConstants.ATTRIBUTE_ROLE_LANGUAGE);
if (langCode!=null) {
template = templates.get(langCode);
}
if (template==null) {
template = templates.get(this.getLangManager().getDefaultLang().getCode());
}
String subject = template.getSubject();
String text = this.replaceParams(template.getBody(), params);
this.getMailManager().sendMail(text, subject, eMail, null, null, config.getEMailSenderCode());
}
private void loadUserDefaultRoles(User user) throws ApsSystemException {
Set<String> roleNames = this.getConfig().getRoles();
if (null != roleNames) {
Iterator<String> it = roleNames.iterator();
while (it.hasNext()) {
String rolename = it.next();
Role role = this.getRoleManager().getRole(rolename);
((IApsAuthorityManager) this.getRoleManager()).setUserAuthorization(user.getUsername(), role);
}
}
}
private void loadUserDefaultGroups(User user) throws ApsSystemException {
Set<String> groupNames = this.getConfig().getGroups();
if (null != groupNames) {
Iterator<String> it = groupNames.iterator();
while (it.hasNext()) {
Group group = this.getGroupManager().getGroup(it.next());
((IApsAuthorityManager) this.getGroupManager()).setUserAuthorization(user.getUsername(), group);
}
}
}
protected void setTokenValidityInMillis(long tokenValidityInMillis) {
this._tokenValidityInMillis = tokenValidityInMillis;
}
protected long getTokenValidityInMillis() {
return _tokenValidityInMillis;
}
protected IUserManager getUserManager() {
return _userManager;
}
public void setUserManager(IUserManager userManager) {
this._userManager = userManager;
}
protected IURLManager getUrlManager() {
return _urlManager;
}
public void setUrlManager(IURLManager urlManager) {
this._urlManager = urlManager;
}
protected IPageManager getPageManager() {
return _pageManager;
}
public void setPageManager(IPageManager pageManager) {
this._pageManager = pageManager;
}
protected IUserProfileManager getUserProfileManager() {
return _userProfileManager;
}
public void setUserProfileManager(IUserProfileManager userProfileManager) {
this._userProfileManager = userProfileManager;
}
protected ConfigInterface getConfigManager() {
return _configManager;
}
public void setConfigManager(ConfigInterface baseConfigManager) {
this._configManager = baseConfigManager;
}
protected ILangManager getLangManager() {
return _langManager;
}
public void setLangManager(ILangManager langManager) {
this._langManager = langManager;
}
protected IMailManager getMailManager() {
return _mailManager;
}
public void setMailManager(IMailManager mailManager) {
this._mailManager = mailManager;
}
protected IGroupManager getGroupManager() {
return _groupManager;
}
public void setGroupManager(IGroupManager groupManager) {
this._groupManager = groupManager;
}
protected IRoleManager getRoleManager() {
return _roleManager;
}
public void setRoleManager(IRoleManager roleManager) {
this._roleManager = roleManager;
}
protected IUserRegDAO getUserRegDAO() {
return _userRegDAO;
}
public void setUserRegDAO(IUserRegDAO activationTocketDAO) {
this._userRegDAO = activationTocketDAO;
}
private long _tokenValidityInMillis;
private IUserRegConfig _userRegConfig;
private IMailManager _mailManager;
private ILangManager _langManager;
private IUserManager _userManager;
private IURLManager _urlManager;
private IPageManager _pageManager;
private IUserProfileManager _userProfileManager;
private ConfigInterface _configManager;
private IGroupManager _groupManager;
private IRoleManager _roleManager;
private IUserRegDAO _userRegDAO;
}