/* * Copyright (C) 2005-2008 Jive Software. All rights reserved. * * 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. */ package org.jivesoftware.openfire.plugin; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.DocumentException; import org.dom4j.Element; import org.jivesoftware.admin.AuthCheckFilter; import org.jivesoftware.openfire.MessageRouter; import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.container.Plugin; import org.jivesoftware.openfire.container.PluginManager; import org.jivesoftware.openfire.event.UserEventDispatcher; import org.jivesoftware.openfire.event.UserEventListener; import org.jivesoftware.openfire.group.Group; import org.jivesoftware.openfire.group.GroupManager; import org.jivesoftware.openfire.group.GroupNotFoundException; import org.jivesoftware.openfire.user.User; import org.jivesoftware.openfire.privacy.PrivacyList; import org.jivesoftware.openfire.privacy.PrivacyListManager; import org.jivesoftware.util.EmailService; import org.jivesoftware.util.JiveGlobals; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xmpp.packet.JID; import org.xmpp.packet.Message; /** * Registration plugin. * * @author Ryan Graham. */ public class RegistrationPlugin implements Plugin { private static final Logger Log = LoggerFactory.getLogger(RegistrationPlugin.class); private static final String URL = "registration/sign-up.jsp"; /** * The expected value is a boolean, if true all contacts specified in the property #IM_CONTACTS * will receive a notification when a new user registers. The default value is false. */ private static final String IM_NOTIFICATION_ENABLED = "registration.imnotification.enabled"; /** * The expected value is a boolean, if true all contacts specified in the property #EMAIL_CONTACTS * will receive a notification when a new user registers. The default value is false. */ private static final String EMAIL_NOTIFICATION_ENABLED = "registration.emailnotification.enabled"; /** * The expected value is a boolean, if true any user who registers will receive the welcome * message specified in the property #WELCOME_MSG. The default value is false. */ private static final String WELCOME_ENABLED = "registration.welcome.enabled"; /** * The expected value is a boolean, if true any user who registers will be added to the group * specified in the property #REGISTRAION_GROUP. The default value is false. */ private static final String GROUP_ENABLED = "registration.group.enabled"; /** * The expected value is a boolean, if true any user who registers will have a Default * privacy list specified in the property #REGISTRAION_PRIVACYLIST. The default value is false. */ private static final String PRIVACYLIST_ENABLED = "registration.privacylist.enabled"; /** * The expected value is a boolean, if true any users will be able to register at the following * url http://[SERVER_NAME}:9090/plugins/registration/sign-up.jsp */ private static final String WEB_ENABLED = "registration.web.enabled"; /** * The expected value is a boolean, if true any users will be need to verify its a human at the * following url http://[SERVER_NAME}:9090/plugins/registration/sign-up.jsp */ private static final String RECAPTCHA_ENABLED = "registration.recaptcha.enabled"; /** * The expected value is a boolean, if true recaptcha uses the noscript tag. */ private static final String RECAPTCHA_NOSCRIPT = "registration.recaptcha.noscript"; /** * The expected value is a String that contains the public key for the recaptcha login. */ private static final String RECAPTCHA_PUBLIC_KEY = "registration.recaptcha.key.public"; /** * The expected value is a String that contains the private key for the recaptcha login. */ private static final String RECAPTCHA_PRIVATE_KEY = "registration.recaptcha.key.private"; /** * The expected value is a comma separated String of usernames who will receive a instant * message when a new user registers if the property #IM_NOTIFICATION_ENABLED is set to true. */ private static final String IM_CONTACTS = "registration.notification.imContacts"; /** * The expected value is a comma separated String of email addresses who will receive an email * when a new user registers, if the property #EMAIL_NOTIFICATION_ENABLED is set to true. */ private static final String EMAIL_CONTACTS = "registration.notification.emailContacts"; /** * The expected value is a String that contains the message that will be sent to a new user * when they register, if the property #WELCOME_ENABLED is set to true. */ private static final String WELCOME_MSG = "registration.welcome.message"; /** * The expected value is a String that contains the name of the group that a new user will * be added to when they register, if the property #GROUP_ENABLED is set to true. */ private static final String REGISTRAION_GROUP = "registration.group"; /** * The expected value is a String that contains the XML contents of the default * privacy list, if the property #PRIVACYLIST_ENABLED is set to true. */ private static final String REGISTRAION_PRIVACYLIST = "registration.privacylist"; /** * The expected value is a String that contains the name of the default * privacy list, if the property #PRIVACYLIST_ENABLED is set to true. */ private static final String REGISTRAION_PRIVACYLIST_NAME = "registration.privacylist.name"; /** * The expected value is a String that contains the text that will be displayed in the header * of the sign-up.jsp, if the property #WEB_ENABLED is set to true. */ private static final String HEADER = "registration.header"; private RegistrationUserEventListener listener = new RegistrationUserEventListener(); private String serverName; private JID serverAddress; private MessageRouter router; private boolean privacyListCacheIsSet = false; private Element privacyListCache = null; private List<String> imContacts = new ArrayList<String>(); private List<String> emailContacts = new ArrayList<String>(); public RegistrationPlugin() { serverName = XMPPServer.getInstance().getServerInfo().getXMPPDomain(); serverAddress = new JID(serverName); router = XMPPServer.getInstance().getMessageRouter(); String imcs = JiveGlobals.getProperty(IM_CONTACTS); if (imcs != null) { imContacts.addAll(Arrays.asList(imcs.split(","))); } String ecs = JiveGlobals.getProperty(EMAIL_CONTACTS); if (ecs != null) { emailContacts.addAll(Arrays.asList(ecs.split(","))); } UserEventDispatcher.addListener(listener); //delete properties from version 1.0 JiveGlobals.deleteProperty("registration.notification.contact"); JiveGlobals.deleteProperty("registration.notification.enabled"); } public void initializePlugin(PluginManager manager, File pluginDirectory) { AuthCheckFilter.addExclude(URL); } public void destroyPlugin() { AuthCheckFilter.removeExclude(URL); UserEventDispatcher.removeListener(listener); serverAddress = null; listener = null; router = null; } public void setIMNotificationEnabled(boolean enable) { JiveGlobals.setProperty(IM_NOTIFICATION_ENABLED, enable ? "true" : "false"); } public boolean imNotificationEnabled() { return JiveGlobals.getBooleanProperty(IM_NOTIFICATION_ENABLED, false); } public void setEmailNotificationEnabled(boolean enable) { JiveGlobals.setProperty(EMAIL_NOTIFICATION_ENABLED, enable ? "true" : "false"); } public boolean emailNotificationEnabled() { return JiveGlobals.getBooleanProperty(EMAIL_NOTIFICATION_ENABLED, false); } public Collection<String> getIMContacts() { Collections.sort(imContacts); return imContacts; } public void addIMContact(String contact) { if (!imContacts.contains(contact.trim().toLowerCase())) { imContacts.add(contact.trim().toLowerCase()); JiveGlobals.setProperty(IM_CONTACTS, propPrep(imContacts)); } } public void removeIMContact(String contact) { imContacts.remove(contact.trim().toLowerCase()); if (imContacts.size() == 0) { JiveGlobals.deleteProperty(IM_CONTACTS); } else { JiveGlobals.setProperty(IM_CONTACTS, propPrep(imContacts)); } } public Collection<String> getEmailContacts() { Collections.sort(emailContacts); return emailContacts; } public void addEmailContact(String contact) { if (!emailContacts.contains(contact.trim())) { emailContacts.add(contact.trim()); JiveGlobals.setProperty(EMAIL_CONTACTS, propPrep(emailContacts)); } } public void removeEmailContact(String contact) { emailContacts.remove(contact); if (emailContacts.size() == 0) { JiveGlobals.deleteProperty(EMAIL_CONTACTS); } else { JiveGlobals.setProperty(EMAIL_CONTACTS, propPrep(emailContacts)); } } public void setWelcomeEnabled(boolean enable) { JiveGlobals.setProperty(WELCOME_ENABLED, enable ? "true" : "false"); } public boolean welcomeEnabled() { return JiveGlobals.getBooleanProperty(WELCOME_ENABLED, false); } public void setWelcomeMessage(String message) { JiveGlobals.setProperty(WELCOME_MSG, message); } public String getWelcomeMessage() { return JiveGlobals.getProperty(WELCOME_MSG, "Welcome to Openfire!"); } public void setGroupEnabled(boolean enable) { JiveGlobals.setProperty(GROUP_ENABLED, enable ? "true" : "false"); } public boolean groupEnabled() { return JiveGlobals.getBooleanProperty(GROUP_ENABLED, false); } public void setPrivacyListEnabled(boolean enable) { JiveGlobals.setProperty(PRIVACYLIST_ENABLED, enable ? "true" : "false"); } public boolean privacyListEnabled() { return JiveGlobals.getBooleanProperty(PRIVACYLIST_ENABLED, false); } public void setWebEnabled(boolean enable) { JiveGlobals.setProperty(WEB_ENABLED, enable ? "true" : "false"); } public boolean webEnabled() { return JiveGlobals.getBooleanProperty(WEB_ENABLED, false); } public String webRegistrationAddress() { return "http://" + XMPPServer.getInstance().getServerInfo().getXMPPDomain() + ":" + JiveGlobals.getXMLProperty("adminConsole.port") + "/plugins/" + URL; } public void setReCaptchaEnabled(boolean enable) { JiveGlobals.setProperty(RECAPTCHA_ENABLED, enable ? "true" : "false"); } public boolean reCaptchaEnabled() { return JiveGlobals.getBooleanProperty(RECAPTCHA_ENABLED, false); } public void setReCaptchaNoScript(boolean enable) { JiveGlobals.setProperty(RECAPTCHA_NOSCRIPT, enable ? "true" : "false"); } public boolean reCaptchaNoScript() { return JiveGlobals.getBooleanProperty(RECAPTCHA_NOSCRIPT, true); } public void setReCaptchaPublicKey(String publicKey) { JiveGlobals.setProperty(RECAPTCHA_PUBLIC_KEY, publicKey); } public String getReCaptchaPublicKey() { return JiveGlobals.getProperty(RECAPTCHA_PUBLIC_KEY); } public void setReCaptchaPrivateKey(String privateKey) { JiveGlobals.setProperty(RECAPTCHA_PRIVATE_KEY, privateKey); } public String getReCaptchaPrivateKey() { return JiveGlobals.getProperty(RECAPTCHA_PRIVATE_KEY); } public void setGroup(String group) { JiveGlobals.setProperty(REGISTRAION_GROUP, group); } public String getGroup() { return JiveGlobals.getProperty(REGISTRAION_GROUP); } public void setPrivacyList(String privacyList) { JiveGlobals.setProperty(REGISTRAION_PRIVACYLIST, privacyList); privacyListCacheIsSet = false; } public String getPrivacyList() { return JiveGlobals.getProperty(REGISTRAION_PRIVACYLIST); } public void setPrivacyListName(String privacyListName) { JiveGlobals.setProperty(REGISTRAION_PRIVACYLIST_NAME, privacyListName); } public String getPrivacyListName() { return JiveGlobals.getProperty(REGISTRAION_PRIVACYLIST_NAME); } public void setHeader(String message) { JiveGlobals.setProperty(HEADER, message); } public String getHeader() { return JiveGlobals.getProperty(HEADER, "Web Sign-In"); } private class RegistrationUserEventListener implements UserEventListener { public void userCreated(User user, Map<String, Object> params) { if (Log.isDebugEnabled()) { Log.debug("Registration plugin : registering new user"); } if (imNotificationEnabled()) { sendIMNotificatonMessage(user); } if (emailNotificationEnabled()) { sendAlertEmail(user); } if (welcomeEnabled()) { sendWelcomeMessage(user); } if (groupEnabled()) { addUserToGroup(user); } if (privacyListEnabled()) { addDefaultPrivacyList(user); } } public void userDeleting(User user, Map<String, Object> params) { } public void userModified(User user, Map<String, Object> params) { } private void sendIMNotificatonMessage(User user) { String msg = " A new user with the username '" + user.getUsername() + "' just registered."; for (String contact : getIMContacts()) { router.route(createServerMessage(contact + "@" + serverName, "Registration Notification", msg)); } } private void sendAlertEmail(User user) { String subject = "User Registration"; String body = " A new user with the username '" + user.getUsername() + "' just registered."; EmailService emailService = EmailService.getInstance(); for (String toAddress : emailContacts) { try { emailService.sendMessage(null, toAddress, "Openfire", "no_reply@" + serverName, subject, body, null); } catch (Exception e) { Log.error(e.getMessage(), e); } } } private void sendWelcomeMessage(User user) { router.route(createServerMessage(user.getUsername() + "@" + serverName, "Welcome", getWelcomeMessage())); } private Message createServerMessage(String to, String subject, String body) { Message message = new Message(); message.setTo(to); message.setFrom(serverAddress); if (subject != null) { message.setSubject(subject); } message.setBody(body); return message; } private void addUserToGroup(User user) { try { GroupManager groupManager = GroupManager.getInstance(); Group group = groupManager.getGroup(getGroup()); group.getMembers().add(XMPPServer.getInstance().createJID(user.getUsername(), null)); } catch (GroupNotFoundException e) { Log.error(e.getMessage(), e); } } private void addDefaultPrivacyList(User user) { if (Log.isDebugEnabled()) { Log.debug("Registration plugin : adding default privacy list."); Log.debug("\tName = "+getPrivacyListName()); Log.debug("\tContent = "+getPrivacyList()); } if(!privacyListCacheIsSet) { privacyListCacheIsSet = true; try { Document document = DocumentHelper.parseText(getPrivacyList()); privacyListCache = document.getRootElement(); } catch (DocumentException e) { Log.error(e.getMessage(), e); } if(privacyListCache == null) { Log.error("registration.privacylist can not be parsed into a valid privacy list"); } } if(privacyListCache != null) { PrivacyListManager privacyListManager = PrivacyListManager.getInstance(); PrivacyList newPrivacyList = privacyListManager.createPrivacyList(user.getUsername(), getPrivacyListName(), privacyListCache); privacyListManager.changeDefaultList(user.getUsername(), newPrivacyList, null); } } } private String propPrep(Collection<String> props) { StringBuilder buf = new StringBuilder(); Iterator<String> iter = props.iterator(); while (iter.hasNext()) { String con = iter.next(); buf.append(con); if (iter.hasNext()) { buf.append(","); } } return buf.toString(); } public boolean isValidAddress(String address) { if (address == null) { return false; } // Must at least match x@x.xx. return address.matches(".{1,}[@].{1,}[.].{2,}"); } }