Commit b94eaa82 authored by Guus der Kinderen's avatar Guus der Kinderen Committed by akrherz

Fixes for OF-1311 and OF-1312 (#772)

* OF-1311: Allow lists to be stored in a property.

* OF-1312: Allow SASL mechanisms to be configured in the admin console.
parent f2a95704
...@@ -1415,6 +1415,32 @@ reg.settings.allowed_ips_blocked_info=Use the form below to define the IP addres ...@@ -1415,6 +1415,32 @@ reg.settings.allowed_ips_blocked_info=Use the form below to define the IP addres
Note that entries on the 'blocked' list (here) will always take precedence over entries on the 'allowed' \ Note that entries on the 'blocked' list (here) will always take precedence over entries on the 'allowed' \
lists below. lists below.
reg.settings.ips_blocked=Do not allow any logins from these IP's: reg.settings.ips_blocked=Do not allow any logins from these IP's:
reg.settings.sasl_mechanisms=SASL Mechanisms
reg.settings.sasl_mechanisms_info=The SASL mechanisms configured below control the mechanism used for authentication. \
Each mechanism has it's own characteristics. The form below is used to control which SASL mechanisms are \
enabled in Openfire. An implementation must be available for the mechanism to be used, but even if one is, the \
mechanism might not be offered to clients after all: this could depend on mechanism-specific server settings.
reg.settings.sasl_mechanisms_columntitle_enabled=Enabled
reg.settings.sasl_mechanisms_columntitle_name=Name
reg.settings.sasl_mechanisms_columntitle_implementation=Implementation available
reg.settings.sasl_mechanisms_columntitle_supported=Offered to clients
reg.settings.sasl_mechanisms_columntitle_description=Description
reg.settings.description.none=(no description available)
reg.settings.description.JIVE-SHAREDSECRET=Proprietary Jive Software SASL mechanism that is based on a shared secret.
reg.settings.description.EXTERNAL=Where authentication is implicit in the context (e.g., for protocols already using IPsec or TLS).
reg.settings.description.ANONYMOUS=For unauthenticated guest access.
reg.settings.description.PLAIN=Simple cleartext password mechanism.
reg.settings.description.OTP=One-time password mechanism.
reg.settings.description.SKEY=An S/KEY mechanism.
reg.settings.description.CRAM-MD5=Simple challenge-response scheme based on HMAC-MD5.
reg.settings.description.DIGEST-MD5=Challenge-response scheme based upon MD5. DIGEST-MD5 offered a data security layer.
reg.settings.description.SCRAM-SHA-1=Salted challenge-response scheme based on SHA-1.
reg.settings.description.SCRAM=Challenge-response scheme based mechanism with channel binding support.
reg.settings.description.NTLM=NT LAN Manager authentication mechanism.
reg.settings.description.GSSAPI=Kerberos V5 authentication via the GSSAPI. GSSAPI offers a data-security layer.
reg.settings.description.EAP-AES128=GSS EAP authentication.
reg.settings.description.OAUTHBEAERER=OAuth, an authentication protocol for delegated resource access.
reg.settings.description.OAUTH10A=OAuth, an authentication protocol for delegated resource access.
# Server db Page # Server db Page
......
...@@ -612,22 +612,49 @@ public class SASLAuthentication { ...@@ -612,22 +612,49 @@ public class SASLAuthentication {
return result; return result;
} }
private static void initMechanisms() /**
* Returns a collection of SASL mechanism names that forms the source pool from which the mechanisms that are
* eventually being offered to peers are obtained.
**
* When a mechanism is not returned by this method, it will never be offered, but when a mechanism is returned
* by this method, there is no guarantee that it will be offered.
*
* Apart from being returned in this method, an implementation must be available (see {@link #getImplementedMechanisms()}
* and configuration or other characteristics of this server must not prevent a particular mechanism from being
* used (see @{link {@link #getSupportedMechanisms()}}.
*
* @return A collection of mechanisms that are considered for use in this instance of Openfire.
*/
public static List<String> getEnabledMechanisms()
{ {
return JiveGlobals.getListProperty("sasl.mechs", Arrays.asList( "ANONYMOUS","PLAIN","DIGEST-MD5","CRAM-MD5","SCRAM-SHA-1","JIVE-SHAREDSECRET","GSSAPI","EXTERNAL" ) );
}
final String configuration = JiveGlobals.getProperty("sasl.mechs", "ANONYMOUS,PLAIN,DIGEST-MD5,CRAM-MD5,SCRAM-SHA-1,JIVE-SHAREDSECRET,GSSAPI,EXTERNAL" ); /**
final StringTokenizer st = new StringTokenizer(configuration, " ,\t\n\r\f"); * Sets the collection of mechanism names that the system administrator allows to be used.
*
* @param mechanisms A collection of mechanisms that are considered for use in this instance of Openfire. Null to reset the default setting.
* @see #getEnabledMechanisms()
*/
public static void setEnabledMechanisms( List<String> mechanisms )
{
JiveGlobals.setProperty( "sasl.mechs", mechanisms );
initMechanisms();
}
private static void initMechanisms()
{
final List<String> propertyValues = getEnabledMechanisms();
mechanisms = new HashSet<>(); mechanisms = new HashSet<>();
while ( st.hasMoreTokens() ) for ( final String propertyValue : propertyValues )
{ {
final String mechanism = st.nextToken().toUpperCase();
try try
{ {
addSupportedMechanism( mechanism ); addSupportedMechanism( propertyValue );
} }
catch ( Exception ex ) catch ( Exception ex )
{ {
Log.warn( "An exception occurred while trying to add support for SASL Mechanism '{}':", mechanism, ex ); Log.warn( "An exception occurred while trying to add support for SASL Mechanism '{}':", propertyValue, ex );
} }
} }
} }
......
...@@ -690,20 +690,66 @@ public class JiveGlobals { ...@@ -690,20 +690,66 @@ public class JiveGlobals {
* @param parent the name of the parent property to return the children for. * @param parent the name of the parent property to return the children for.
* @return all child property values for the given parent. * @return all child property values for the given parent.
*/ */
public static List<String> getProperties(String parent) { public static List<String> getProperties( String parent )
if (properties == null) { {
if (isSetupMode()) { return getListProperty( parent, new ArrayList<String>() );
return new ArrayList<>(); }
/**
* Return all immediate children property values of a parent Jive property as a list of strings, or an default list
* if the property does not exist.
*
* This implementation ignores child property values that are empty (these are excluded from the result). When all
* child properties are empty, an empty collection (and explicitly not the default values) is returned. This allows
* a property to override a default non-empty collection with an empty one.
*
* The child properties that are evaluated in this method are the same child properties as those used by
* {@link #getProperties(String)}.
*
* @param parent the name of the parent property to return the children for.
* @param defaultValues values returned if the property doesn't exist.
* @return all child property values for the given parent.
*/
public static List<String> getListProperty( String parent, List<String> defaultValues )
{
if ( properties == null )
{
if ( isSetupMode() )
{
return defaultValues;
} }
properties = JiveProperties.getInstance(); properties = JiveProperties.getInstance();
} }
Collection<String> propertyNames = properties.getChildrenNames(parent); // Check for a legacy, comma separated value.
List<String> values = new ArrayList<>(); final String legacyValue = JiveGlobals.getProperty( parent );
for (String propertyName : propertyNames) {
String value = getProperty(propertyName); final Collection<String> propertyNames = properties.getChildrenNames( parent );
if (value != null) { if ( propertyNames.isEmpty() )
values.add(value); {
if ( legacyValue != null )
{
Log.info( "Retrieving a list from property '{}' which is stored in a comma-separated format. Consider using child properties instead, via JiveGlobals.setProperty( String value, List<String> values )", parent );
return Arrays.asList( legacyValue.split( "\\s*,\\s*" ) );
}
// When there are no child properties, return the default values.
return defaultValues;
}
else if ( legacyValue != null )
{
// Raise a warning if two competing sets of data are detected.
Log.warn( "Retrieving a list from property '{}' which is stored using child properties, but also in a legacy format! The data that is in the legacy format (the text value of property '{}') is not returned by this call! Its child property values are used instead. Consider removing the text value of the parent property.", parent, parent );
}
// When there are child properties, return its non-null, non-empty values (which might be an empty collection).
final List<String> values = new ArrayList<>();
for ( String propertyName : propertyNames )
{
final String value = getProperty( propertyName );
if ( value != null && !value.isEmpty())
{
values.add( value );
} }
} }
...@@ -743,8 +789,74 @@ public class JiveGlobals { ...@@ -743,8 +789,74 @@ public class JiveGlobals {
} }
/** /**
* Sets multiple Jive properties at once. If a property doesn't already exists, a new * Sets a Jive property with a list of values. If the property doesn't already exists, a new one will be created.
* one will be created. * Empty or null values in the collection are ignored.
*
* Each value is stored as a direct child property of the property name provided as an argument to this method. When
* this method is used, all previous children of the property will be deleted.
*
* When the provided value is null, any previously stored collection will be removed. If it is an empty collection
* (or a collection that consists of null and empty values onlu), it is stored as an empty collection
* (represented by a child property that has an empty value).
*
* The naming convention used by this method to define child properties is subject to change, and should not be
* depended on.
*
* This method differs from {@link #setProperties(Map)}, which is used to set multiple properties. This method sets
* one property with multiple values.
*
* @param name the name of the property being set.
* @param values the values of the property.
*/
public static void setProperty( String name, List<String> values )
{
if ( properties == null )
{
if ( isSetupMode() )
{
return;
}
properties = JiveProperties.getInstance();
}
final List<String> existing = getProperties( name );
if ( existing != null && existing.equals( values ) )
{
// no change.
return;
}
properties.remove( name );
if ( values != null )
{
int i = 1;
for ( final String value : values )
{
if ( value != null && !value.isEmpty() )
{
final String childName = name + "." + i++;
properties.put( childName, value );
}
}
// When no non-null, non-empty values are stored, store one to denote an empty collection.
if ( i == 1 )
{
properties.put( name + ".1", "" );
}
// The put's above will have generated events for each child property. Now, generate an event for the parent.
final Map<String, Object> params = new HashMap<>();
params.put("value", values);
PropertyEventDispatcher.dispatchEvent(name, PropertyEventDispatcher.EventType.property_set, params);
}
}
/**
* Sets multiple Jive properties at once. If a property doesn't already exists, a new one will be created.
*
* This method differs from {@link #setProperty(String, List)}, which is used to one property with multiple
* values. This method sets multiple properties, each with one value.
* *
* @param propertyMap a map of properties, keyed on property name. * @param propertyMap a map of properties, keyed on property name.
*/ */
......
This diff is collapsed.
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