Commit 4ba3e173 authored by Guus der Kinderen's avatar Guus der Kinderen

OF-477: Improve default XMPP domain name and FQDN

This commit intends to have better default values for two properties of Openfire:
- the XMPP domain name (eg: igniterealtime.org)
- the FQDN of the server (eg: xmpp.igniterealtime.org)

Older code did not always make a clear distinction (ambiguously referring to
'server name'). Having a proper FQDN has become more important, as newer SASL
implementations depend on the client using the same FQDN as what is configured
in the server).

This commit removes support for changing the XMPP domain name at run time (although
you can obviously still change the corresponding property). Instead, the FQDN can
now be changes (although will require a restart).

Additionally, the XMPPServerInfo implementation got a bit of a refactoring: values
that are not expected to be modified (or considered unmodifiable from a functional
perspective), are no longer passed around, but are rather hardcoded in the
implementation. Support for deprecated ServerPort was removed.

Finally, most access to the properties that hold the XMPP domain name and FQDN
are now encapsulated by XMPPServerInfoImpl.
parent de1344ff
......@@ -1037,8 +1037,8 @@ index.version=Version:
index.home=Server Directory:
index.certificate-warning=Found RSA certificate that is not valid for the server domain.
index.certificate-error=Unable to access certificate store. The keystore may be corrupt.
index.server_name=Server Name:
index.host_name=Host Name:
index.server_name=XMPP Domain Name:
index.host_name=Server Host Name (FQDN):
index.server_port=Server Ports
index.server_ip=IP:Port, Security:
index.port_type=NORMAL
......@@ -1520,7 +1520,7 @@ server.props.update.norestart=Server properties updated successfully
server.props.update=Server properties updated successfully. You'll need to
server.props.update2=the server to have the changes take effect (see
server.props.property=Server Properties
server.props.name=Server Name:
server.props.name=Server Host Name (FQDN):
server.props.valid_hostname=Please enter a valid server host name or
server.props.valid_hostname1=restore the default
server.props.server_port=Server-to-Server Port:
......@@ -2116,11 +2116,13 @@ setup.finished.wait=Please wait, finishing setup...
# Setup host settings Page
setup.host.settings.title=Server Settings
setup.host.settings.info=Below are host settings for this server. Note: the suggested value for the \
domain is based on the network settings of this machine.
setup.host.settings.domain=Domain:
setup.host.settings.info=Below are network settings for this server.
setup.host.settings.domain=XMPP Domain Name:
setup.host.settings.domain.help=The name of the XMPP domain that this server will be part of (for example: example.org). If this server will be part of an Openfire cluster, each server must have the same XMPP domain name.
setup.host.settings.invalid_domain=Invalid domain.
setup.host.settings.hostname=Hostname or IP address of this server.
setup.host.settings.fqdn=Server Host Name (FQDN):
setup.host.settings.fqdn.help=The fully qualified domain name of this server (for example: openfire.example.org). If this server will be part of an Openfire cluster, each server must have the same host name.
setup.host.settings.invalid_fqdn=Invalid host name.
setup.host.settings.port=Admin Console Port:
setup.host.settings.secure_port=Secure Admin Console Port:
setup.host.settings.invalid_port=Invalid port number
......
......@@ -61,8 +61,6 @@ import org.xmpp.packet.JID;
import java.io.*;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
......@@ -104,10 +102,6 @@ public class XMPPServer {
private static XMPPServer instance;
private String name;
private String host;
private Version version;
private Date startDate;
private boolean initialized = false;
private boolean started = false;
private NodeID nodeID;
......@@ -189,12 +183,9 @@ public class XMPPServer {
* @param jid the JID to check.
* @return true if the address is a local address to this server.
*/
public boolean isLocal(JID jid) {
boolean local = false;
if (jid != null && name != null && name.equals(jid.getDomain())) {
local = true;
}
return local;
public boolean isLocal( JID jid )
{
return jid != null && jid.getDomain().equals( xmppServerInfo.getXMPPDomain() );
}
/**
......@@ -205,13 +196,11 @@ public class XMPPServer {
* @return true if the given address does not match the local server hostname and does not
* match a component service JID.
*/
public boolean isRemote(JID jid) {
if (jid != null) {
if (!name.equals(jid.getDomain()) && !componentManager.hasComponent(jid)) {
return true;
}
}
return false;
public boolean isRemote( JID jid )
{
return jid != null
&& !jid.getDomain().equals( xmppServerInfo.getXMPPDomain() )
&& !componentManager.hasComponent( jid );
}
/**
......@@ -242,8 +231,11 @@ public class XMPPServer {
* @param jid the JID to check.
* @return true if the given address matches a component service JID.
*/
public boolean matchesComponent(JID jid) {
return jid != null && !name.equals(jid.getDomain()) && componentManager.hasComponent(jid);
public boolean matchesComponent( JID jid )
{
return jid != null
&& !jid.getDomain().equals( xmppServerInfo.getXMPPDomain() )
&& componentManager.hasComponent( jid );
}
/**
......@@ -254,7 +246,7 @@ public class XMPPServer {
* @return an XMPPAddress for the server.
*/
public JID createJID(String username, String resource) {
return new JID(username, name, resource);
return new JID(username, xmppServerInfo.getXMPPDomain(), resource);
}
/**
......@@ -267,7 +259,7 @@ public class XMPPServer {
* @return an XMPPAddress for the server.
*/
public JID createJID(String username, String resource, boolean skipStringprep) {
return new JID(username, name, resource, skipStringprep);
return new JID(username, xmppServerInfo.getXMPPDomain(), resource, skipStringprep);
}
/**
......@@ -303,19 +295,6 @@ public class XMPPServer {
private void initialize() throws FileNotFoundException {
locateOpenfire();
startDate = new Date();
try {
host = InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException ex) {
logger.warn("Unable to determine local hostname.", ex);
}
if (host == null) {
host = "127.0.0.1";
}
version = new Version(4, 1, 0, Version.ReleaseStatus.Beta, -1);
if ("true".equals(JiveGlobals.getXMLProperty("setup"))) {
setupMode = false;
}
......@@ -336,13 +315,12 @@ public class XMPPServer {
}
JiveGlobals.migrateProperty("xmpp.domain");
name = JiveGlobals.getProperty("xmpp.domain", host).toLowerCase();
JiveGlobals.migrateProperty(Log.LOG_DEBUG_ENABLED);
Log.setDebugEnabled(JiveGlobals.getBooleanProperty(Log.LOG_DEBUG_ENABLED, false));
// Update server info
xmppServerInfo = new XMPPServerInfoImpl(name, host, version, startDate);
xmppServerInfo = new XMPPServerInfoImpl(new Date());
initialized = true;
}
......@@ -358,10 +336,6 @@ public class XMPPServer {
}
// Make sure that setup finished correctly.
if ("true".equals(JiveGlobals.getXMLProperty("setup"))) {
// Set the new server domain assigned during the setup process
name = JiveGlobals.getProperty("xmpp.domain").toLowerCase();
xmppServerInfo.setXMPPDomain(name);
// Iterate through all the provided XML properties and set the ones that haven't
// already been touched by setup prior to this method being called.
for (String propName : JiveGlobals.getXMLPropertyNames()) {
......@@ -461,7 +435,7 @@ public class XMPPServer {
pluginManager.start();
// Log that the server has been started
String startupBanner = LocaleUtils.getLocalizedString("short.title") + " " + version.getVersionString() +
String startupBanner = LocaleUtils.getLocalizedString("short.title") + " " + xmppServerInfo.getVersion().getVersionString() +
" [" + JiveGlobals.formatDateTime(new Date()) + "]";
logger.info(startupBanner);
System.out.println(startupBanner);
......
......@@ -42,28 +42,31 @@ public interface XMPPServerInfo {
Version getVersion();
/**
* Obtain the host name (IP address or hostname) of this server node.
* Obtain the fully qualified domain name (hostname or IP address) of this server node.
*
* @return the server's host name as an IP address or host name.
* @return the server's host name.
*/
String getHostname();
/**
* Obtain the server XMPP domain name. Note that, if unconfigured, the
* returned value will equal the hostname or IP address of the server.
* Sets the fully qualified domain name of this server node. Preferrably, this is a network name, but can be an
* IP address.
*
* @return the name of the XMPP domain that this server is part of.
* Note that some SASL implementations depend on the client sending the same FQDN value as the one that is
* configured in the server.
*
* When setting a new host name, the server note must be restarted.
*
* @param fqdn The hostname. When null or empty, a system default will be used instead.
*/
String getXMPPDomain();
void setHostname( String fqdn );
/**
* Set the server XMPP domain name. The server must be
* restarted for this change to take effect.
* Obtain the server XMPP domain name, which is equal for all server nodes in an Openfire cluster.
*
* @param domainName
* the XMPP domain that this server is part of.
* @return the name of the XMPP domain that this server is part of.
*/
void setXMPPDomain(String domainName);
String getXMPPDomain();
/**
* Obtain the date when the server was last started.
......@@ -71,11 +74,4 @@ public interface XMPPServerInfo {
* @return the date the server was started or null if server has not been started.
*/
Date getLastStarted();
/**
* Obtain the server ports active on this server.
*
* @return an iterator over the server ports for this server.
*/
Collection<ServerPort> getServerPorts();
}
\ No newline at end of file
......@@ -20,16 +20,8 @@
package org.jivesoftware.openfire.net;
import java.io.IOException;
import java.util.Map;
import java.util.TimerTask;
import javax.jmdns.JmDNS;
import javax.jmdns.ServiceInfo;
import org.jivesoftware.openfire.ServerPort;
import org.jivesoftware.openfire.ConnectionManager;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.XMPPServerInfo;
import org.jivesoftware.openfire.container.BasicModule;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.PropertyEventDispatcher;
......@@ -38,6 +30,12 @@ import org.jivesoftware.util.TaskEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jmdns.JmDNS;
import javax.jmdns.ServiceInfo;
import java.io.IOException;
import java.util.Map;
import java.util.TimerTask;
/**
* Publishes Openfire information as a service using the Multicast DNS (marketed by Apple
* as Rendezvous) protocol. This lets other nodes on the local network to discover
......@@ -107,16 +105,13 @@ public class MulticastDNSService extends BasicModule {
TimerTask startService = new TimerTask() {
@Override
public void run() {
XMPPServerInfo info = XMPPServer.getInstance().getServerInfo();
int clientPortNum = -1;
int componentPortNum = -1;
for (ServerPort port : info.getServerPorts()) {
if (port.isClientPort()) {
clientPortNum = port.getPort();
}
else if (port.isComponentPort()) {
componentPortNum = port.getPort();
}
final ConnectionManager connectionManager = XMPPServer.getInstance().getConnectionManager();
if ( connectionManager != null )
{
clientPortNum = connectionManager.getClientListenerPort();
componentPortNum = connectionManager.getComponentListenerPort();
}
try {
if (jmdns == null) {
......
......@@ -27,6 +27,7 @@ import org.dom4j.Namespace;
import org.dom4j.QName;
import org.jivesoftware.openfire.Connection;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.XMPPServerInfo;
import org.jivesoftware.openfire.auth.AuthFactory;
import org.jivesoftware.openfire.auth.AuthToken;
import org.jivesoftware.openfire.keystore.CertificateStoreManager;
......@@ -265,15 +266,14 @@ public class SASLAuthentication {
// OF-477: The SASL implementation requires the fully qualified host name (not the domain name!) of this server,
// yet, most of the XMPP implemenations of DIGEST-MD5 will actually use the domain name. To account for that,
// here, we'll use the host name, unless DIGEST-MD5 is being negotiated!
final String fqhn = JiveGlobals.getProperty( "xmpp.fqdn", XMPPServer.getInstance().getServerInfo().getHostname() );
final String fqdn = XMPPServer.getInstance().getServerInfo().getXMPPDomain();
final String serverName = ( mechanismName.equals( "DIGEST-MD5" ) ? fqdn : fqhn );
final XMPPServerInfo serverInfo = XMPPServer.getInstance().getServerInfo();
final String serverName = ( mechanismName.equals( "DIGEST-MD5" ) ? serverInfo.getXMPPDomain() : serverInfo.getHostname() );
// Construct the configuration properties
final Map<String, Object> props = new HashMap<>();
props.put( LocalSession.class.getCanonicalName(), session );
props.put( Sasl.POLICY_NOANONYMOUS, Boolean.toString( !JiveGlobals.getBooleanProperty( "xmpp.auth.anonymous" ) ) );
props.put( "com.sun.security.sasl.digest.realm", fqdn );
props.put( "com.sun.security.sasl.digest.realm", serverInfo.getXMPPDomain() );
SaslServer saslServer = Sasl.createSaslServer( mechanismName, "xmpp", serverName, props, new XMPPCallbackHandler() );
if ( saslServer == null )
......
......@@ -20,15 +20,14 @@
package org.jivesoftware.openfire.spi;
import org.jivesoftware.openfire.ConnectionManager;
import org.jivesoftware.openfire.ServerPort;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.XMPPServerInfo;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Version;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Collections;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
/**
......@@ -39,69 +38,62 @@ import java.util.Date;
*/
public class XMPPServerInfoImpl implements XMPPServerInfo {
private Date startDate;
private String xmppDomain;
private String hostname;
private Version ver;
private ConnectionManager connectionManager;
private static final Logger Log = LoggerFactory.getLogger( XMPPServerInfoImpl.class );
private final Date startDate;
public static final Version VERSION = new Version(4, 1, 0, Version.ReleaseStatus.Beta, -1 );
/**
* Simple constructor
*
* @param xmppDomain the server's XMPP domain name (e.g. example.org).
* @param hostname the server's host name (e.g. server1.example.org).
* @param version the server's version number.
* @param startDate the server's last start time (can be null indicating
* it hasn't been started).
*/
public XMPPServerInfoImpl(String xmppDomain, String hostname, Version version, Date startDate) {
this.xmppDomain = xmppDomain;
this.hostname = hostname;
this.ver = version;
public XMPPServerInfoImpl(Date startDate) {
this.startDate = startDate;
}
@Override
public Version getVersion() {
return ver;
return VERSION;
}
@Override
public String getHostname()
{
return hostname;
}
@Override
public String getXMPPDomain()
{
return xmppDomain;
try
{
return JiveGlobals.getProperty( "xmpp.fqdn", InetAddress.getLocalHost().getCanonicalHostName() ).toLowerCase();
}
catch (UnknownHostException ex)
{
Log.warn( "Unable to determine local hostname.", ex );
return "localhost";
}
}
@Override
public void setXMPPDomain(String domainName)
{
this.xmppDomain = domainName;
if (domainName == null) {
JiveGlobals.deleteProperty("xmpp.domain");
public void setHostname( String fqdn )
{
if ( fqdn == null || fqdn.isEmpty() )
{
JiveGlobals.deleteProperty( "xmpp.fqdn" );
}
else {
JiveGlobals.setProperty("xmpp.domain", domainName);
else
{
JiveGlobals.setProperty( "xmpp.fqdn", fqdn.toLowerCase() );
}
}
@Override
public String getXMPPDomain()
{
return JiveGlobals.getProperty("xmpp.domain", getHostname() ).toLowerCase();
}
@Override
public Date getLastStarted() {
return startDate;
}
@Override
public Collection<ServerPort> getServerPorts() {
if (connectionManager == null) {
connectionManager = XMPPServer.getInstance().getConnectionManager();
}
return connectionManager == null ?
Collections.<ServerPort>emptyList() :
connectionManager.getPorts();
}
}
\ No newline at end of file
......@@ -133,7 +133,7 @@
if (errors.size() == 0) {
boolean needRestart = false;
if (!serverName.equals(server.getServerInfo().getXMPPDomain())) {
server.getServerInfo().setXMPPDomain(serverName);
server.getServerInfo().setHostname(serverName);
needRestart = true;
}
connectionManager.setClientListenerPort(port);
......@@ -163,7 +163,7 @@
return;
}
} else {
serverName = server.getServerInfo().getXMPPDomain();
serverName = server.getServerInfo().getHostname();
sslEnabled = connectionManager.isClientSSLListenerEnabled();
port = connectionManager.getClientListenerPort();
sslPort = connectionManager.getClientSSLListenerPort();
......
......@@ -26,6 +26,7 @@
<% // Get parameters
String domain = ParamUtils.getParameter(request, "domain");
String fqdn = ParamUtils.getParameter(request, "fqdn");
int embeddedPort = ParamUtils.getIntParameter(request, "embeddedPort", Integer.MIN_VALUE);
int securePort = ParamUtils.getIntParameter(request, "securePort", Integer.MIN_VALUE);
boolean sslEnabled = ParamUtils.getBooleanParameter(request, "sslEnabled", true);
......@@ -39,9 +40,12 @@
Map<String, String> errors = new HashMap<String, String>();
if (doContinue) {
// Validate parameters
if (domain == null) {
if (domain == null || domain.isEmpty()) {
errors.put("domain", "domain");
}
if (fqdn == null || fqdn.isEmpty()) {
errors.put("fqdn", "fqdn");
}
if (XMPPServer.getInstance().isStandAlone()) {
if (embeddedPort == Integer.MIN_VALUE) {
errors.put("embeddedPort", "embeddedPort");
......@@ -75,6 +79,7 @@
Map<String, String> xmppSettings = new HashMap<String, String>();
xmppSettings.put("xmpp.domain", domain);
xmppSettings.put("xmpp.fqdn", fqdn);
xmppSettings.put("xmpp.socket.ssl.active", "" + sslEnabled);
xmppSettings.put("xmpp.auth.anonymous", "" + anonymousAuthentication);
session.setAttribute("xmppSettings", xmppSettings);
......@@ -96,19 +101,30 @@
// Load the current values:
if (!doContinue) {
domain = JiveGlobals.getXMLProperty("xmpp.domain");
fqdn = JiveGlobals.getXMLProperty("xmpp.fqdn");
embeddedPort = JiveGlobals.getXMLProperty("adminConsole.port", 9090);
securePort = JiveGlobals.getXMLProperty("adminConsole.securePort", 9091);
sslEnabled = JiveGlobals.getXMLProperty("xmpp.socket.ssl.active", true);
// If the domain is still blank, guess at the value:
if (domain == null) {
try {
domain = InetAddress.getLocalHost().getHostName().toLowerCase();
} catch (UnknownHostException e) {
e.printStackTrace();
domain = "127.0.0.1";
// If the fqdn (server name) is still blank, guess:
if (fqdn == null || fqdn.isEmpty())
{
try
{
fqdn = InetAddress.getLocalHost().getCanonicalHostName();
}
catch (UnknownHostException ex)
{
System.err.println( "Unable to determine the fully qualified domain name (canonical hostname) of this server." );
ex.printStackTrace();
fqdn = "localhost";
}
}
// If the domain is still blank, use the host name.
if (domain == null) {
domain = fqdn;
}
}
%>
......@@ -141,7 +157,7 @@
<td width="99%">
<input type="text" size="30" maxlength="150" name="domain"
value="<%= ((domain != null) ? domain : "") %>">
<span class="jive-setup-helpicon" onmouseover="domTT_activate(this, event, 'content', '<fmt:message key="setup.host.settings.hostname" />', 'styleClass', 'jiveTooltip', 'trail', true, 'delay', 300, 'lifetime', 8000);"></span>
<span class="jive-setup-helpicon" onmouseover="domTT_activate(this, event, 'content', '<fmt:message key="setup.host.settings.domain.help" />', 'styleClass', 'jiveTooltip', 'trail', true, 'delay', 300, 'lifetime', 8000);"></span>
<% if (errors.get("domain") != null) { %>
<span class="jive-error-text">
<fmt:message key="setup.host.settings.invalid_domain" />
......@@ -149,6 +165,22 @@
<% } %>
</td>
</tr>
<tr valign="top">
<td width="1%" nowrap align="right">
<fmt:message key="setup.host.settings.fqdn" />
</td>
<td width="99%">
<input type="text" size="30" maxlength="150" name="fqdn"
value="<%= ((fqdn != null) ? fqdn : "") %>">
<span class="jive-setup-helpicon" onmouseover="domTT_activate(this, event, 'content', '<fmt:message key="setup.host.settings.fqdn.help" />', 'styleClass', 'jiveTooltip', 'trail', true, 'delay', 300, 'lifetime', 8000);"></span>
<% if (errors.get("fqdn") != null) { %>
<span class="jive-error-text">
<fmt:message key="setup.host.settings.invalid_fqdn" />
</span>
<% } %>
</td>
</tr>
<% if (XMPPServer.getInstance().isStandAlone()){ %>
<tr valign="top">
<td width="1%" nowrap align="right">
......
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