Commit 793734b6 authored by Daniel Henninger's avatar Daniel Henninger Committed by dhenninger

Ported changes from 3.5.0 branch.


git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@9982 b35dd754-fafc-0310-a699-88a17e54d16e
parent 10081d25
......@@ -183,6 +183,7 @@ hr {
<li>[<a href='http://www.igniterealtime.org/issues/browse/JM-1241'>JM-1241</a>] - XMPPServerInfo now makes a distinction between 'hostname' and 'xmpp domain name'.</li>
<li>[<a href='http://www.igniterealtime.org/issues/browse/JM-1270'>JM-1270</a>] - Changed default HTTP binding ports to 7070 and 7443.</li>
<li>[<a href='http://www.igniterealtime.org/issues/browse/JM-1271'>JM-1271</a>] - Updated MINA library to latest version.</li>
<li>[<a href='http://www.igniterealtime.org/issues/browse/JM-1276'>JM-1276</a>] - Added functionality to UserProvider to allow requirement of email and name fields.</li>
</ul>
<h3>Openfire Bug Fixes</h3>
......
......@@ -155,6 +155,10 @@ public class AuthorizationManager {
if (UserManager.getUserProvider().isReadOnly()) {
return false;
}
if (UserManager.getUserProvider().isNameRequired() || UserManager.getUserProvider().isEmailRequired()) {
// If these are required, there's no way we can arbitrarily auto-create this account.
return false;
}
try {
UserManager.getUserProvider().createUser(username, StringUtils.randomString(8), null, null);
if (Log.isDebugEnabled()) {
......
......@@ -82,7 +82,6 @@ public class ClearspaceUserProvider implements UserProvider {
passwordE.addText(password);
// adds the the email
//todo in CS the email is mandatory
Element emailE = userE.addElement("email");
emailE.addText(email);
......@@ -332,6 +331,14 @@ public class ClearspaceUserProvider implements UserProvider {
return (readOnly == null ? false : readOnly);
}
public boolean isNameRequired() {
return false;
}
public boolean isEmailRequired() {
return true;
}
private void loadReadOnly() {
try {
// See if the is read only
......
......@@ -34,6 +34,8 @@ import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.jivesoftware.stringprep.Stringprep;
import org.jivesoftware.stringprep.StringprepException;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.PacketError;
......@@ -123,11 +125,17 @@ public class IQRegisterHandler extends IQHandler implements ServerFeaturesProvid
field = new XFormFieldImpl("name");
field.setType(FormField.TYPE_TEXT_SINGLE);
field.setLabel("Full name");
if (UserManager.getUserProvider().isNameRequired()) {
field.setRequired(true);
}
registrationForm.addField(field);
field = new XFormFieldImpl("email");
field.setType(FormField.TYPE_TEXT_SINGLE);
field.setLabel("Email");
if (UserManager.getUserProvider().isEmailRequired()) {
field.setRequired(true);
}
registrationForm.addField(field);
field = new XFormFieldImpl("password");
......@@ -298,6 +306,11 @@ public class IQRegisterHandler extends IQHandler implements ServerFeaturesProvid
if (email == null || "".equals(email)) {
email = " ";
}
// So that we can set a more informative error message back, lets test this for
// stringprep validity now.
if (username != null) {
Stringprep.nodeprep(username);
}
if (session.getStatus() == Session.STATUS_AUTHENTICATED) {
// Flag that indicates if the user is *only* changing his password
......@@ -384,12 +397,18 @@ public class IQRegisterHandler extends IQHandler implements ServerFeaturesProvid
reply.setChildElement(packet.getChildElement().createCopy());
reply.setError(PacketError.Condition.bad_request);
}
catch (IllegalArgumentException e) {
catch (StringprepException e) {
// The specified username is not correct according to the stringprep specs
reply = IQ.createResultIQ(packet);
reply.setChildElement(packet.getChildElement().createCopy());
reply.setError(PacketError.Condition.jid_malformed);
}
catch (IllegalArgumentException e) {
// At least one of the fields passed in is not valid
reply = IQ.createResultIQ(packet);
reply.setChildElement(packet.getChildElement().createCopy());
reply.setError(PacketError.Condition.not_acceptable);
}
catch (UnsupportedOperationException e) {
// The User provider is read-only so this operation is not allowed
reply = IQ.createResultIQ(packet);
......
......@@ -711,6 +711,14 @@ public class LdapUserProvider implements UserProvider {
return true;
}
public boolean isNameRequired() {
return false;
}
public boolean isEmailRequired() {
return false;
}
/**
* Parses dates/time stamps stored in LDAP. Some possible values:
*
......
......@@ -499,4 +499,12 @@ public class DefaultUserProvider implements UserProvider {
public boolean isReadOnly() {
return false;
}
public boolean isNameRequired() {
return false;
}
public boolean isEmailRequired() {
return false;
}
}
......@@ -402,4 +402,12 @@ public class JDBCUserProvider implements UserProvider {
public boolean isReadOnly() {
return true;
}
public boolean isNameRequired() {
return false;
}
public boolean isEmailRequired() {
return false;
}
}
......@@ -18,6 +18,7 @@ import org.jivesoftware.openfire.event.UserEventDispatcher;
import org.jivesoftware.openfire.resultsetmanager.Result;
import org.jivesoftware.openfire.roster.Roster;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.StringUtils;
import org.jivesoftware.util.cache.CacheSizes;
import org.jivesoftware.util.cache.Cacheable;
import org.jivesoftware.util.cache.ExternalizableUtil;
......@@ -106,7 +107,9 @@ public class User implements Cacheable, Externalizable, Result {
}
/**
* Constructs a new user. All arguments can be <tt>null</tt> except the username.
* Constructs a new user. Normally, all arguments can be <tt>null</tt> except the username.
* However, a UserProvider -may- require a name or email address. In those cases, the
* isNameRequired or isEmailRequired UserProvider tests indicate whether <tt>null</tt> is allowed.
* Typically, User objects should not be constructed by end-users of the API.
* Instead, user objects should be retrieved using {@link UserManager#getUser(String)}.
*
......@@ -123,7 +126,13 @@ public class User implements Cacheable, Externalizable, Result {
throw new NullPointerException("Username cannot be null");
}
this.username = username;
if (UserManager.getUserProvider().isNameRequired() && (name == null || name.equals(""))) {
throw new IllegalArgumentException("Invalid or empty name specified with provider that requires name");
}
this.name = name;
if (UserManager.getUserProvider().isEmailRequired() && !StringUtils.isValidEmailAddress(email)) {
throw new IllegalArgumentException("Invalid or empty email address specified with provider that requires email address");
}
this.email = email;
this.creationDate = creationDate;
this.modificationDate = modificationDate;
......@@ -174,6 +183,10 @@ public class User implements Cacheable, Externalizable, Result {
throw new UnsupportedOperationException("User provider is read-only.");
}
if ((name == null || name.equals("")) && UserManager.getUserProvider().isNameRequired()) {
throw new IllegalArgumentException("User provider requires name.");
}
try {
String originalName = this.name;
UserManager.getUserProvider().setName(username, name);
......@@ -205,6 +218,10 @@ public class User implements Cacheable, Externalizable, Result {
throw new UnsupportedOperationException("User provider is read-only.");
}
if (UserManager.getUserProvider().isEmailRequired() && !StringUtils.isValidEmailAddress(email)) {
throw new IllegalArgumentException("User provider requires email address.");
}
try {
String originalEmail= this.email;
UserManager.getUserProvider().setEmail(username, email);
......
......@@ -116,13 +116,15 @@ public class UserManager implements IQResultListener {
/**
* Creates a new User. Required values are username and password. The email address
* can optionally be <tt>null</tt>.
* and name can optionally be <tt>null</tt>, unless the UserProvider deems that
* either of them are required.
*
* @param username the new and unique username for the account.
* @param password the password for the account (plain text).
* @param name the name of the user.
* @param name the name of the user, which can be <tt>null</tt> unless the UserProvider
* deems that it's required.
* @param email the email address to associate with the new account, which can
* be <tt>null</tt>.
* be <tt>null</tt>, unless the UserProvider deems that it's required.
* @return a new User.
* @throws UserAlreadyExistsException if the username already exists in the system.
* @throws UnsupportedOperationException if the provider does not support the
......@@ -141,6 +143,12 @@ public class UserManager implements IQResultListener {
catch (StringprepException se) {
throw new IllegalArgumentException("Invalid username: " + username, se);
}
if (provider.isNameRequired() && (name == null || name.equals(""))) {
throw new IllegalArgumentException("Invalid or empty name specified with provider that requires name");
}
if (provider.isEmailRequired() && !StringUtils.isValidEmailAddress(email)) {
throw new IllegalArgumentException("Invalid or empty email address specified with provider that requires email address");
}
User user = provider.createUser(username, password, name, email);
userCache.put(username, user);
......
......@@ -38,8 +38,8 @@ public interface UserProvider {
*
* @param username the username.
* @param password the plain-text password.
* @param name the user's name, which can be <tt>null</tt>.
* @param email the user's email address, which can be <tt>null</tt>.
* @param name the user's name, which can be <tt>null</tt>, unless isNameRequired is set to true.
* @param email the user's email address, which can be <tt>null</tt>, unless isEmailRequired is set to true.
* @return a new User.
* @throws UserAlreadyExistsException if the username is already in use.
*/
......@@ -208,4 +208,19 @@ public interface UserProvider {
* @return true if the user provider is read-only.
*/
public boolean isReadOnly();
/**
* Returns true if this UserProvider requires a name to be set on User objects.
*
* @return true if an name is required with this provider.
*/
public boolean isNameRequired();
/**
* Returns true if this UserProvider requires an email address to be set on User objects.
*
* @return true if an email address is required with this provider.
*/
public boolean isEmailRequired();
}
\ No newline at end of file
......@@ -10,6 +10,8 @@
package org.jivesoftware.util;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.AddressException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
......@@ -1007,4 +1009,28 @@ public class StringUtils {
return str.substring(0, maxWidth) + "...";
}
/**
* Returns true if the string passed in is a valid Email address.
*
* @param address Email address to test for validity.
* @return true if the string passed in is a valid email address.
*/
public static boolean isValidEmailAddress(String address) {
if (address == null) {
return false;
}
if (!address.contains("@")) {
return false;
}
try {
InternetAddress.parse(address);
return true;
}
catch (AddressException e) {
return false;
}
}
}
\ No newline at end of file
......@@ -71,6 +71,18 @@
if (password != null && passwordConfirm != null && !password.equals(passwordConfirm)) {
errors.put("passwordMatch","");
}
// If provider requires email, validate
if (UserManager.getUserProvider().isEmailRequired()) {
if (StringUtils.isValidEmailAddress(email)) {
errors.put("email","");
}
}
// If provider requires name, validate
if (UserManager.getUserProvider().isNameRequired()) {
if (name == null || name.equals("")) {
errors.put("name","");
}
}
// do a create if there were no errors
if (errors.size() == 0) {
......@@ -185,9 +197,7 @@
</td>
</tr>
<tr>
<td width="1%" nowrap>
<label for="nametf"><fmt:message key="user.create.name" />:</label>
</td>
<td width="1%" nowrap><label for="nametf"><fmt:message key="user.create.name" />:</label> <%= UserManager.getUserProvider().isNameRequired() ? "*" : "" %></td>
<td width="99%">
<input type="text" name="name" size="30" maxlength="75" value="<%= ((name!=null) ? name : "") %>"
id="nametf">
......@@ -195,7 +205,7 @@
</tr>
<tr>
<td width="1%" nowrap>
<label for="emailtf"><fmt:message key="user.create.email" />:</label></td>
<label for="emailtf"><fmt:message key="user.create.email" />:</label> <%= UserManager.getUserProvider().isEmailRequired() ? "*" : "" %></td>
<td width="99%">
<input type="text" name="email" size="30" maxlength="75" value="<%= ((email!=null) ? email : "") %>"
id="emailtf">
......
......@@ -14,6 +14,9 @@
errorPage="error.jsp"
%><%@ page import="org.xmpp.packet.JID"%>
<%@ page import="org.jivesoftware.openfire.security.SecurityAuditManager" %>
<%@ page import="org.jivesoftware.util.StringUtils" %>
<%@ page import="java.util.Map" %>
<%@ page import="java.util.HashMap" %>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %>
......@@ -26,6 +29,7 @@
String username = ParamUtils.getParameter(request,"username");
String name = ParamUtils.getParameter(request,"name");
String email = ParamUtils.getParameter(request,"email");
Map<String, String> errors = new HashMap<String, String>();
// Handle a cancel
if (request.getParameter("cancel") != null) {
......@@ -38,6 +42,19 @@
// Handle a save
if (save) {
// If provider requires email, validate
if (UserManager.getUserProvider().isEmailRequired()) {
if (StringUtils.isValidEmailAddress(email)) {
errors.put("email","");
}
}
// If provider requires name, validate
if (UserManager.getUserProvider().isNameRequired()) {
if (name == null || name.equals("")) {
errors.put("name","");
}
}
user.setEmail(email);
user.setName(name);
......@@ -59,8 +76,28 @@
<meta name="extraParams" content="<%= "username="+URLEncoder.encode(username, "UTF-8") %>"/>
</head>
<body>
<% if (!errors.isEmpty()) { %>
<% if (success) { %>
<div class="jive-error">
<table cellpadding="0" cellspacing="0" border="0">
<tbody>
<tr>
<td class="jive-icon"><img src="images/error-16x16.gif" width="16" height="16" border="0" alt=""/></td>
<td class="jive-icon-label">
<% if (errors.get("name") != null) { %>
<fmt:message key="user.create.invalid_name" />
<% } else if (errors.get("email") != null) { %>
<fmt:message key="user.create.invalid_email" />
<% } %>
</td>
</tr>
</tbody>
</table>
</div>
<br>
<% } else if (success) { %>
<div class="jive-success">
<table cellpadding="0" cellspacing="0" border="0">
......@@ -99,7 +136,7 @@
</tr>
<tr>
<td class="c1">
<fmt:message key="user.create.name" />:
<fmt:message key="user.create.name" />: <%= UserManager.getUserProvider().isNameRequired() ? "*" : "" %>
</td>
<td>
<input type="text" size="30" maxlength="150" name="name"
......@@ -108,7 +145,7 @@
</tr>
<tr>
<td class="c1">
<fmt:message key="user.create.email" />:
<fmt:message key="user.create.email" />: <%= UserManager.getUserProvider().isEmailRequired() ? "*" : "" %>
</td>
<td>
<input type="text" size="30" maxlength="150" name="email"
......@@ -118,6 +155,7 @@
</tbody>
</table>
</div>
</fieldset>
<br><br>
......@@ -127,5 +165,11 @@
</form>
<br/>
<span class="jive-description">
* <fmt:message key="user.create.requied" />
</span>
</body>
</html>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment