/* * (C) Copyright 2011-2014 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * 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. * Contributors: * Nuxeo - initial API and implementation */ package org.nuxeo.ecm.user.invite; import static org.apache.commons.lang.StringUtils.isBlank; import static org.nuxeo.ecm.user.invite.RegistrationRules.FACET_REGISTRATION_CONFIGURATION; import static org.nuxeo.ecm.user.invite.RegistrationRules.FIELD_CONFIGURATION_NAME; import static org.nuxeo.ecm.user.invite.UserInvitationService.ValidationMethod.EMAIL; import static org.nuxeo.ecm.user.invite.UserRegistrationConfiguration.DEFAULT_CONFIGURATION_NAME; import java.io.IOException; import java.io.Serializable; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import javax.naming.InitialContext; import javax.naming.NamingException; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuxeo.ecm.core.api.CoreSession; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.DocumentModelList; import org.nuxeo.ecm.core.api.DocumentRef; import org.nuxeo.ecm.core.api.IdRef; import org.nuxeo.ecm.core.api.NuxeoException; import org.nuxeo.ecm.core.api.NuxeoPrincipal; import org.nuxeo.ecm.core.api.PathRef; import org.nuxeo.ecm.core.api.PropertyException; import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner; import org.nuxeo.ecm.core.api.impl.DocumentModelImpl; import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl; import org.nuxeo.ecm.core.api.pathsegment.PathSegmentService; import org.nuxeo.ecm.core.api.repository.RepositoryManager; import org.nuxeo.ecm.core.api.security.ACE; import org.nuxeo.ecm.core.api.security.ACL; import org.nuxeo.ecm.core.api.security.ACP; import org.nuxeo.ecm.core.event.Event; import org.nuxeo.ecm.core.event.EventContext; import org.nuxeo.ecm.core.event.EventService; import org.nuxeo.ecm.core.event.impl.DocumentEventContext; import org.nuxeo.ecm.platform.rendering.api.RenderingException; import org.nuxeo.ecm.platform.usermanager.NuxeoPrincipalImpl; import org.nuxeo.ecm.platform.usermanager.UserConfig; import org.nuxeo.ecm.platform.usermanager.UserManager; import org.nuxeo.ecm.platform.usermanager.exceptions.UserAlreadyExistsException; import org.nuxeo.runtime.api.Framework; import org.nuxeo.runtime.model.ComponentInstance; import org.nuxeo.runtime.model.DefaultComponent; public class UserInvitationComponent extends DefaultComponent implements UserInvitationService { protected static Log log = LogFactory.getLog(UserInvitationService.class); public static final String NUXEO_URL_KEY = "nuxeo.url"; protected String repoName = null; protected String testRendering = null; protected RenderingHelper rh = new RenderingHelper(); protected Map<String, UserRegistrationConfiguration> configurations = new HashMap<String, UserRegistrationConfiguration>(); private static final String INVITATION_SUBMITTED_EVENT = "invitationSubmitted"; private static final String INVITATION_ACCEPTED_EVENT = "invitationAccepted"; private static final String INVITATION_REJECTED_EVENT = "invitationRejected"; private static final String INVITATION_VALIDATED_EVENT = "invitationValidated"; public String getTestedRendering() { return testRendering; } protected String getTargetRepositoryName() { if (repoName == null) { RepositoryManager rm = Framework.getService(RepositoryManager.class); repoName = rm.getDefaultRepositoryName(); } return repoName; } protected boolean userAlreadyExists(UserRegistrationInfo userRegistrationInfo) { DocumentModel user = Framework.getLocalService(UserManager.class).getUserModel(userRegistrationInfo.getLogin()); return user != null; } protected String getJavaMailJndiName() { return Framework.getProperty("jndi.java.mail", "java:/Mail"); } @Override public DocumentModel getUserRegistrationModel(String configurationName) { // Test if the configuration is defined if (StringUtils.isEmpty(configurationName)) { configurationName = DEFAULT_CONFIGURATION_NAME; } // Get the DocumentModel for the doctype defined in the configuration UserRegistrationModelCreator creator = new UserRegistrationModelCreator(configurationName); creator.runUnrestricted(); return creator.getUserRegistrationModel(); } @Override public DocumentModel getRegistrationRulesDocument(CoreSession session, String configurationName) { // By default, configuration is hold by the root request document return getOrCreateRootDocument(session, configurationName); } public DocumentModel getOrCreateRootDocument(CoreSession session, String configurationName) { UserRegistrationConfiguration configuration = getConfiguration(configurationName); String targetPath = configuration.getContainerParentPath() + configuration.getContainerName(); DocumentRef targetRef = new PathRef(targetPath); DocumentModel root; if (!session.exists(targetRef)) { root = session.createDocumentModel(configuration.getContainerDocType()); root.setPathInfo(configuration.getContainerParentPath(), configuration.getContainerName()); root.setPropertyValue("dc:title", configuration.getContainerTitle()); // XXX ACLs ?!!! root = session.createDocument(root); } else { root = session.getDocument(targetRef); } // Add configuration facet if (!root.hasFacet(FACET_REGISTRATION_CONFIGURATION)) { root.addFacet(FACET_REGISTRATION_CONFIGURATION); root.setPropertyValue(FIELD_CONFIGURATION_NAME, configuration.getName()); root = session.saveDocument(root); } return root; } protected class UserRegistrationModelCreator extends UnrestrictedSessionRunner { DocumentModel userRegistrationModel; protected UserRegistrationConfiguration configuration; public UserRegistrationModelCreator(String configurationName) { super(getTargetRepositoryName()); configuration = getConfiguration(configurationName); } @Override public void run() { userRegistrationModel = session.createDocumentModel(configuration.getRequestDocType()); } public DocumentModel getUserRegistrationModel() { return userRegistrationModel; } } protected class RegistrationCreator extends UnrestrictedSessionRunner { protected Map<String, Serializable> additionnalInfo; protected String registrationUuid; protected ValidationMethod validationMethod; protected DocumentModel userRegistrationModel; protected UserRegistrationConfiguration configuration; public String getRegistrationUuid() { return registrationUuid; } public RegistrationCreator(String configurationName, DocumentModel userRegistrationModel, Map<String, Serializable> additionnalInfo, ValidationMethod validationMethod) { super(getTargetRepositoryName()); this.userRegistrationModel = userRegistrationModel; this.additionnalInfo = additionnalInfo; this.validationMethod = validationMethod; configuration = getConfiguration(configurationName); } @Override public void run() { String title = "registration request for " + userRegistrationModel.getPropertyValue(configuration.getUserInfoUsernameField()) + " (" + userRegistrationModel.getPropertyValue(configuration.getUserInfoEmailField()) + " " + userRegistrationModel.getPropertyValue(configuration.getUserInfoCompanyField()) + ") "; PathSegmentService pss = Framework.getLocalService(PathSegmentService.class); String name = pss.generatePathSegment(title + "-" + System.currentTimeMillis()); String targetPath = getOrCreateRootDocument(session, configuration.getName()).getPathAsString(); userRegistrationModel.setPathInfo(targetPath, name); userRegistrationModel.setPropertyValue("dc:title", title); // validation method userRegistrationModel.setPropertyValue("registration:validationMethod", validationMethod.toString()); // additionnal infos if (additionnalInfo != null && !additionnalInfo.isEmpty()) { for (String key : additionnalInfo.keySet()) { try { userRegistrationModel.setPropertyValue(key, additionnalInfo.get(key)); } catch (PropertyException e) { // skip silently } } } userRegistrationModel = session.createDocument(userRegistrationModel); registrationUuid = userRegistrationModel.getId(); sendEvent(session, userRegistrationModel, getNameEventRegistrationSubmitted()); session.save(); } } protected class RegistrationApprover extends UnrestrictedSessionRunner { private final UserManager userManager; protected String uuid; protected Map<String, Serializable> additionnalInfo; public RegistrationApprover(String registrationUuid, Map<String, Serializable> additionnalInfo) { super(getTargetRepositoryName()); uuid = registrationUuid; this.additionnalInfo = additionnalInfo; this.userManager = Framework.getLocalService(UserManager.class); } @Override public void run() { DocumentModel doc = session.getDocument(new IdRef(uuid)); String validationMethod = (String) doc.getPropertyValue("registration:validationMethod"); NuxeoPrincipal targetPrincipal = userManager.getPrincipal((String) doc.getPropertyValue("userinfo:login")); if (targetPrincipal == null) { targetPrincipal = userManager.getPrincipal((String) doc.getPropertyValue("userinfo:email")); } if (targetPrincipal != null) { DocumentModel target = session.getDocument(new IdRef( (String) doc.getPropertyValue("docinfo:documentId"))); ACP acp = target.getACP(); Map<String, Serializable> contextData = new HashMap<>(); contextData.put("notify", true); contextData.put("comment", doc.getPropertyValue("registration:comment")); acp.addACE(ACL.LOCAL_ACL, ACE.builder(targetPrincipal.getName(), (String) doc.getPropertyValue("docinfo:permission")) .creator((String) doc.getPropertyValue("docinfo:creator")) .contextData(contextData) .build()); target.setACP(acp, true); // test Validation Method } else if (StringUtils.equals(EMAIL.toString(), validationMethod)) { sendValidationEmail(additionnalInfo, doc); } doc.setPropertyValue("registration:accepted", true); if (doc.getAllowedStateTransitions().contains("approve")) { doc.followTransition("approve"); } doc = session.saveDocument(doc); session.save(); sendEvent(session, doc, getNameEventRegistrationAccepted()); } } protected class RegistrationRejector extends UnrestrictedSessionRunner { protected String uuid; protected Map<String, Serializable> additionnalInfo; public RegistrationRejector(String registrationUuid, Map<String, Serializable> additionnalInfo) { super(getTargetRepositoryName()); uuid = registrationUuid; this.additionnalInfo = additionnalInfo; } @Override public void run() { DocumentModel doc = session.getDocument(new IdRef(uuid)); doc.setPropertyValue("registration:accepted", false); if (doc.getAllowedStateTransitions().contains("reject")) { doc.followTransition("reject"); } doc = session.saveDocument(doc); session.save(); sendEvent(session, doc, getNameEventRegistrationRejected()); } } protected class RegistrationAcceptator extends UnrestrictedSessionRunner { protected String uuid; protected Map<String, Serializable> registrationData = new HashMap<String, Serializable>(); protected Map<String, Serializable> additionnalInfo; public RegistrationAcceptator(String uuid, Map<String, Serializable> additionnalInfo) { super(getTargetRepositoryName()); this.uuid = uuid; this.additionnalInfo = additionnalInfo; } public Map<String, Serializable> getRegistrationData() { return registrationData; } @Override public void run() { DocumentRef idRef = new IdRef(uuid); DocumentModel registrationDoc = session.getDocument(idRef); // additionnal infos for (String key : additionnalInfo.keySet()) { try { if (DefaultInvitationUserFactory.PASSWORD_KEY.equals(key)) { // add the password as a transient context data registrationDoc.putContextData(DefaultInvitationUserFactory.PASSWORD_KEY, additionnalInfo.get(key)); } else { registrationDoc.setPropertyValue(key, additionnalInfo.get(key)); } } catch (PropertyException e) { // skip silently } } if (registrationDoc.getLifeCyclePolicy().equals("registrationRequest")) { if (registrationDoc.getCurrentLifeCycleState().equals("approved")) { registrationDoc.followTransition("accept"); } else { if (registrationDoc.getCurrentLifeCycleState().equals("accepted")) { throw new AlreadyProcessedRegistrationException( "Registration request has already been processed"); } else { throw new UserRegistrationException("Registration request has not been accepted yet"); } } } session.saveDocument(registrationDoc); session.save(); EventContext evContext = sendEvent(session, registrationDoc, getNameEventRegistrationValidated()); ((DocumentModelImpl) registrationDoc).detach(sessionIsAlreadyUnrestricted); registrationData.put(REGISTRATION_DATA_DOC, registrationDoc); registrationData.put(REGISTRATION_DATA_USER, evContext.getProperty("registeredUser")); } } protected class RequestIdValidator extends UnrestrictedSessionRunner { protected String uuid; public RequestIdValidator(String uuid) { super(getTargetRepositoryName()); this.uuid = uuid; } @Override public void run() { DocumentRef idRef = new IdRef(uuid); // Check if the id matches an existing document if (!session.exists(idRef)) { throw new UserRegistrationException("There is no existing registration request with id " + uuid); } // Check if the request has not been already validated DocumentModel registrationDoc = session.getDocument(idRef); if (registrationDoc.getCurrentLifeCycleState().equals("accepted")) { throw new AlreadyProcessedRegistrationException("Registration request has already been processed"); } } } protected EventContext sendEvent(CoreSession session, DocumentModel source, String evName) throws UserRegistrationException { try { EventService evService = Framework.getService(EventService.class); EventContext evContext = new DocumentEventContext(session, session.getPrincipal(), source); Event event = evContext.newEvent(evName); evService.fireEvent(event); return evContext; } catch (UserRegistrationException ue) { log.warn("Error during event processing", ue); throw ue; } } protected void sendValidationEmail(Map<String, Serializable> additionnalInfo, DocumentModel registrationDoc) { UserRegistrationConfiguration configuration = getConfiguration(registrationDoc); sendEmail(additionnalInfo, registrationDoc, configuration.getValidationEmailTemplate(), configuration.getValidationEmailTitle()); } protected void sendEmail(Map<String, Serializable> additionnalInfo, DocumentModel registrationDoc, String emailTemplatePath, String emailTitle) { UserRegistrationConfiguration configuration = getConfiguration(registrationDoc); String emailAdress = (String) registrationDoc.getPropertyValue(configuration.getUserInfoEmailField()); Map<String, Serializable> input = new HashMap<String, Serializable>(); Map<String, Serializable> userinfo = new HashMap<String, Serializable>(); userinfo.put("firstName", registrationDoc.getPropertyValue(configuration.getUserInfoFirstnameField())); userinfo.put("lastName", registrationDoc.getPropertyValue(configuration.getUserInfoLastnameField())); userinfo.put("login", registrationDoc.getPropertyValue(configuration.getUserInfoUsernameField())); userinfo.put("id", registrationDoc.getId()); String documentTitle = ""; if (registrationDoc.hasSchema("docinfo")) { documentTitle = (String) registrationDoc.getPropertyValue("docinfo:documentTitle"); } input.put("documentTitle", documentTitle); input.put("configurationName", configuration.getName()); input.put("comment", registrationDoc.getPropertyValue("registration:comment")); input.put(UserInvitationService.REGISTRATION_CONFIGURATION_NAME, configuration.getName()); input.put("userinfo", (Serializable) userinfo); input.put("info", (Serializable) additionnalInfo); input.put("userAlreadyExists", checkUserFromRegistrationExistence(registrationDoc)); input.put("productName", Framework.getProperty("org.nuxeo.ecm.product.name")); StringWriter writer = new StringWriter(); try { rh.getRenderingEngine().render(emailTemplatePath, input, writer); } catch (RenderingException e) { throw new NuxeoException("Error during rendering email", e); } // render custom email subject emailTitle = renderSubjectTemplate(emailTitle, input); String body = writer.getBuffer().toString(); String copyTo = (String) registrationDoc.getPropertyValue("registration:copyTo"); if (!isTestModeSet()) { try { generateMail(emailAdress, copyTo, emailTitle, body); } catch (NamingException | MessagingException e) { throw new NuxeoException("Error while sending mail: ", e); } } else { testRendering = body; } } private String renderSubjectTemplate(String emailTitle, Map<String, Serializable> input) { Configuration stringCfg = rh.getEngineConfiguration(); Writer out; try { Template templ = new Template("subjectTemplate", new StringReader(emailTitle), stringCfg); out = new StringWriter(); templ.process(input, out); out.flush(); } catch (IOException | TemplateException e) { throw new NuxeoException("Error while rendering email subject: ", e); } return out.toString(); } protected static boolean isTestModeSet() { return Framework.isTestModeSet() || !isBlank(Framework.getProperty("org.nuxeo.ecm.tester.name")); } protected boolean checkUserFromRegistrationExistence(DocumentModel registrationDoc) { UserRegistrationConfiguration configuration = getConfiguration(registrationDoc); return null != Framework.getLocalService(UserManager.class).getPrincipal( (String) registrationDoc.getPropertyValue(configuration.getUserInfoUsernameField())); } protected void generateMail(String destination, String copy, String title, String content) throws NamingException, MessagingException { InitialContext ic = new InitialContext(); Session session = (Session) ic.lookup(getJavaMailJndiName()); MimeMessage msg = new MimeMessage(session); msg.setFrom(new InternetAddress(session.getProperty("mail.from"))); msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(destination, false)); if (!isBlank(copy)) { msg.addRecipient(Message.RecipientType.CC, new InternetAddress(copy, false)); } msg.setSubject(title, "UTF-8"); msg.setSentDate(new Date()); msg.setContent(content, "text/html; charset=utf-8"); Transport.send(msg); } @Override public String submitRegistrationRequest(DocumentModel userRegistrationModel, Map<String, Serializable> additionnalInfo, ValidationMethod validationMethod, boolean autoAccept) { return submitRegistrationRequest(DEFAULT_CONFIGURATION_NAME, userRegistrationModel, additionnalInfo, validationMethod, autoAccept); } @Override public DocumentModelList getRegistrationsForUser(final String docId, final String username, final String configurationName) { final DocumentModelList registrationDocs = new DocumentModelListImpl(); new UnrestrictedSessionRunner(getTargetRepositoryName()) { @Override public void run() { String query = "SELECT * FROM Document WHERE ecm:currentLifeCycleState != 'validated' AND" + " ecm:mixinType = '" + getConfiguration(configurationName).getRequestDocType() + "' AND docinfo:documentId = '%s' AND" + getConfiguration(configurationName).getUserInfoUsernameField() + " = '%s' AND ecm:isCheckedInVersion = 0"; query = String.format(query, docId, username); registrationDocs.addAll(session.query(query)); } }.runUnrestricted(); return registrationDocs; } protected static boolean isEmailExist(UserRegistrationConfiguration configuration, DocumentModel userRegistration) { String email = (String) userRegistration.getPropertyValue(configuration.getUserInfoEmailField()); if (isBlank(email)) { return false; } Map<String, Serializable> filter = new HashMap<>(1); filter.put(UserConfig.EMAIL_COLUMN, email); DocumentModelList users = Framework.getLocalService(UserManager.class).searchUsers(filter, null); return !users.isEmpty(); } @Override public String submitRegistrationRequest(String configurationName, DocumentModel userRegistrationModel, Map<String, Serializable> additionnalInfo, ValidationMethod validationMethod, boolean autoAccept) { RegistrationCreator creator = new RegistrationCreator(configurationName, userRegistrationModel, additionnalInfo, validationMethod); creator.runUnrestricted(); String registrationUuid = creator.getRegistrationUuid(); UserRegistrationConfiguration currentConfig = getConfiguration(configurationName); boolean userAlreadyExists = null != Framework.getLocalService(UserManager.class).getPrincipal( (String) userRegistrationModel.getPropertyValue(currentConfig.getUserInfoUsernameField())); if (!userAlreadyExists && isEmailExist(currentConfig, userRegistrationModel)) { log.info("Trying to submit a registration from an existing email with a different username."); throw new UserAlreadyExistsException(); } // Directly accept registration if the configuration allow it and the // user already exists RegistrationRules registrationRules = getRegistrationRules(configurationName); boolean byPassAdminValidation = autoAccept; byPassAdminValidation |= userAlreadyExists && registrationRules.allowDirectValidationForExistingUser(); byPassAdminValidation |= registrationRules.allowDirectValidationForExistingUser() && registrationRules.allowDirectValidationForNonExistingUser(); if (byPassAdminValidation) { // Build validationBaseUrl with nuxeo.url property as request is not // accessible. if (!additionnalInfo.containsKey("enterPasswordUrl")) { additionnalInfo.put("enterPasswordUrl", buildEnterPasswordUrl(currentConfig)); } acceptRegistrationRequest(registrationUuid, additionnalInfo); } return registrationUuid; } protected String buildEnterPasswordUrl(UserRegistrationConfiguration configuration) { String baseUrl = Framework.getProperty(NUXEO_URL_KEY); baseUrl = isBlank(baseUrl) ? "/" : baseUrl; if (!baseUrl.endsWith("/")) { baseUrl += "/"; } return baseUrl.concat(configuration.getEnterPasswordUrl()); } @Override public void acceptRegistrationRequest(String requestId, Map<String, Serializable> additionnalInfo) throws UserRegistrationException { RegistrationApprover acceptor = new RegistrationApprover(requestId, additionnalInfo); acceptor.runUnrestricted(); } @Override public void rejectRegistrationRequest(String requestId, Map<String, Serializable> additionnalInfo) throws UserRegistrationException { RegistrationRejector rejector = new RegistrationRejector(requestId, additionnalInfo); rejector.runUnrestricted(); } @Override public Map<String, Serializable> validateRegistration(String requestId, Map<String, Serializable> additionnalInfo) throws UserRegistrationException { RegistrationAcceptator validator = new RegistrationAcceptator(requestId, additionnalInfo); validator.runUnrestricted(); return validator.getRegistrationData(); } @Override public Map<String, Serializable> validateRegistrationAndSendEmail(String requestId, Map<String, Serializable> additionnalInfo) throws UserRegistrationException { Map<String, Serializable> registrationInfo = validateRegistration(requestId, additionnalInfo); Map<String, Serializable> input = new HashMap<String, Serializable>(); input.putAll(registrationInfo); input.put("info", (Serializable) additionnalInfo); StringWriter writer = new StringWriter(); UserRegistrationConfiguration configuration = getConfiguration((DocumentModel) registrationInfo.get(REGISTRATION_DATA_DOC)); try { rh.getRenderingEngine().render(configuration.getSuccessEmailTemplate(), input, writer); } catch (RenderingException e) { throw new NuxeoException("Error during rendering email", e); } String emailAdress = ((NuxeoPrincipalImpl) registrationInfo.get("registeredUser")).getEmail(); String body = writer.getBuffer().toString(); String title = configuration.getValidationEmailTitle(); if (!Framework.isTestModeSet()) { try { generateMail(emailAdress, null, title, body); } catch (NamingException | MessagingException e) { throw new NuxeoException("Error while sending mail : ", e); } } else { testRendering = body; } return registrationInfo; } @Override public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { if ("configuration".equals(extensionPoint)) { UserRegistrationConfiguration newConfig = (UserRegistrationConfiguration) contribution; if (configurations.containsKey(newConfig.getName())) { if (newConfig.isMerge()) { configurations.get(newConfig.getName()).mergeWith(newConfig); } else if (newConfig.isRemove()) { configurations.remove(newConfig.getName()); } else { log.warn("Trying to register an existing userRegistration configuration without removing or merging it, in: " + contributor.getName()); } } else { configurations.put(newConfig.getName(), newConfig); } } } protected InvitationUserFactory getRegistrationUserFactory(UserRegistrationConfiguration configuration) { InvitationUserFactory factory = null; Class<? extends InvitationUserFactory> factoryClass = configuration.getRegistrationUserFactory(); if (factoryClass != null) { try { factory = factoryClass.newInstance(); } catch (InstantiationException e) { log.warn("Failed to instanciate RegistrationUserFactory", e); } catch (IllegalAccessException e) { log.warn("Failed to instanciate RegistrationUserFactory", e); } } if (factory == null) { factory = new DefaultInvitationUserFactory(); } return factory; } @Override public NuxeoPrincipal createUser(CoreSession session, DocumentModel registrationDoc) throws UserRegistrationException { UserRegistrationConfiguration configuration = getConfiguration(registrationDoc); return getRegistrationUserFactory(configuration).doCreateUser(session, registrationDoc, configuration); } protected class RootDocumentGetter extends UnrestrictedSessionRunner { protected DocumentModel doc; protected String configurationName; protected RootDocumentGetter(String configurationName) { super(getTargetRepositoryName()); this.configurationName = configurationName; } @Override public void run() { doc = getOrCreateRootDocument(session, configurationName); ((DocumentModelImpl) doc).detach(true); } public DocumentModel getDoc() { return doc; } } @Override public UserRegistrationConfiguration getConfiguration() { return getConfiguration(DEFAULT_CONFIGURATION_NAME); } @Override public UserRegistrationConfiguration getConfiguration(DocumentModel requestDoc) { try { DocumentModel parent = requestDoc.getCoreSession().getDocument(requestDoc.getParentRef()); String configurationName = DEFAULT_CONFIGURATION_NAME; if (parent.hasFacet(FACET_REGISTRATION_CONFIGURATION)) { configurationName = (String) parent.getPropertyValue(FIELD_CONFIGURATION_NAME); } else if (requestDoc.hasFacet(FACET_REGISTRATION_CONFIGURATION)) { configurationName = (String) requestDoc.getPropertyValue(FIELD_CONFIGURATION_NAME); } if (!configurations.containsKey(configurationName)) { throw new NuxeoException("Configuration " + configurationName + " is not registered"); } return configurations.get(configurationName); } catch (NuxeoException e) { log.info("Unable to get request parent document: " + e.getMessage()); throw e; } } @Override public UserRegistrationConfiguration getConfiguration(String name) { if (!configurations.containsKey(name)) { throw new NuxeoException("Trying to get unknown user registration configuration."); } return configurations.get(name); } @Override public RegistrationRules getRegistrationRules(String configurationName) { RootDocumentGetter rdg = new RootDocumentGetter(configurationName); rdg.runUnrestricted(); return rdg.getDoc().getAdapter(RegistrationRules.class); } @Override public void reviveRegistrationRequests(CoreSession session, List<DocumentModel> registrationDocs) { for (DocumentModel registrationDoc : registrationDocs) { reviveRegistrationRequest(session, registrationDoc, new HashMap<String, Serializable>()); } } protected void reviveRegistrationRequest(CoreSession session, DocumentModel registrationDoc, Map<String, Serializable> additionalInfos) { UserRegistrationConfiguration configuration = getConfiguration(registrationDoc); // Build validationBaseUrl with nuxeo.url property as request is not // accessible. if (!additionalInfos.containsKey("enterPasswordUrl")) { additionalInfos.put("enterPasswordUrl", buildEnterPasswordUrl(configuration)); } sendEmail(additionalInfos, registrationDoc, configuration.getReviveEmailTemplate(), configuration.getReviveEmailTitle()); } @Override public void deleteRegistrationRequests(CoreSession session, List<DocumentModel> registrationDocs) { for (DocumentModel registration : registrationDocs) { UserRegistrationConfiguration configuration = getConfiguration(registration); if (!registration.hasSchema(configuration.getUserInfoSchemaName())) { throw new NuxeoException("Registration document do not contains needed schema"); } session.removeDocument(registration.getRef()); } } @Override public Set<String> getConfigurationsName() { return configurations.keySet(); } @Override public void checkRequestId(final String requestId) throws UserRegistrationException { RequestIdValidator runner = new RequestIdValidator(requestId); runner.runUnrestricted(); } @Override public String getNameEventRegistrationSubmitted() { return INVITATION_SUBMITTED_EVENT; } @Override public String getNameEventRegistrationAccepted() { return INVITATION_ACCEPTED_EVENT; } @Override public String getNameEventRegistrationRejected() { return INVITATION_REJECTED_EVENT; } @Override public String getNameEventRegistrationValidated() { return INVITATION_VALIDATED_EVENT; } }