Commit 130fc97e authored by Dave Cridland's avatar Dave Cridland

Merge pull request #572 from guusdk/OF-1124

Various SASL-related changes
parents 61423720 cd0a3201
...@@ -35,15 +35,14 @@ import org.jivesoftware.openfire.sasl.JiveSharedSecretSaslServer; ...@@ -35,15 +35,14 @@ import org.jivesoftware.openfire.sasl.JiveSharedSecretSaslServer;
import org.jivesoftware.openfire.sasl.SaslFailureException; import org.jivesoftware.openfire.sasl.SaslFailureException;
import org.jivesoftware.openfire.session.*; import org.jivesoftware.openfire.session.*;
import org.jivesoftware.openfire.spi.ConnectionType; import org.jivesoftware.openfire.spi.ConnectionType;
import org.jivesoftware.util.CertificateManager; import org.jivesoftware.util.*;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.security.sasl.Sasl; import javax.security.sasl.Sasl;
import javax.security.sasl.SaslException; import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer; import javax.security.sasl.SaslServer;
import javax.security.sasl.SaslServerFactory;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.Security; import java.security.Security;
import java.security.cert.Certificate; import java.security.cert.Certificate;
...@@ -84,7 +83,42 @@ public class SASLAuthentication { ...@@ -84,7 +83,42 @@ public class SASLAuthentication {
// Add (proprietary) Providers of SASL implementation to the Java security context. // Add (proprietary) Providers of SASL implementation to the Java security context.
Security.addProvider( new org.jivesoftware.openfire.sasl.SaslProvider() ); Security.addProvider( new org.jivesoftware.openfire.sasl.SaslProvider() );
// Convert XML based provider setup to Database based
JiveGlobals.migrateProperty("sasl.mechs");
JiveGlobals.migrateProperty("sasl.gssapi.debug");
JiveGlobals.migrateProperty("sasl.gssapi.config");
JiveGlobals.migrateProperty("sasl.gssapi.useSubjectCredsOnly");
initMechanisms(); initMechanisms();
org.jivesoftware.util.PropertyEventDispatcher.addListener( new PropertyEventListener()
{
@Override
public void propertySet( String property, Map<String, Object> params )
{
if ("sasl.mechs".equals( property ) )
{
initMechanisms();
}
}
@Override
public void propertyDeleted( String property, Map<String, Object> params )
{
if ("sasl.mechs".equals( property ) )
{
initMechanisms();
}
}
@Override
public void xmlPropertySet( String property, Map<String, Object> params )
{}
@Override
public void xmlPropertyDeleted( String property, Map<String, Object> params )
{}
} );
} }
public enum ElementType public enum ElementType
...@@ -471,59 +505,117 @@ public class SASLAuthentication { ...@@ -471,59 +505,117 @@ public class SASLAuthentication {
* *
* @return the list of supported SASL mechanisms by the server. * @return the list of supported SASL mechanisms by the server.
*/ */
public static Set<String> getSupportedMechanisms() { public static Set<String> getSupportedMechanisms()
Set<String> answer = new HashSet<>(mechanisms); {
// Clean up not-available mechanisms // List all mechanism names for which there's an implementation.
for (Iterator<String> it=answer.iterator(); it.hasNext();) { final Set<String> implementedMechanisms = getImplementedMechanisms();
String mech = it.next();
if (mech.equals("CRAM-MD5") || mech.equals("DIGEST-MD5")) { // Start off with all mechanisms that we intend to support.
// Check if the user provider in use supports passwords retrieval. Accessing final Set<String> answer = new HashSet<>( mechanisms );
// to the users passwords will be required by the CallbackHandler
if (!AuthFactory.supportsPasswordRetrieval()) { // Clean up not-available mechanisms.
it.remove(); for ( final Iterator<String> it = answer.iterator(); it.hasNext(); )
} {
} final String mechanism = it.next();
else if (mech.equals("SCRAM-SHA-1")) {
if (!AuthFactory.supportsPasswordRetrieval() && !AuthFactory.supportsScram()) { if ( !implementedMechanisms.contains( mechanism ) )
it.remove(); {
} Log.trace( "Cannot support '{}' as there's no implementation available.", mechanism );
} it.remove();
else if (mech.equals("ANONYMOUS")) { continue;
// Check anonymous is supported
if (!JiveGlobals.getBooleanProperty( "xmpp.auth.anonymous" )) {
it.remove();
}
} }
else if (mech.equals("JIVE-SHAREDSECRET")) {
// Check shared secret is supported switch ( mechanism )
if (!JiveSharedSecretSaslServer.isSharedSecretAllowed()) { {
it.remove(); case "CRAM-MD5": // intended fall-through
} case "DIGEST-MD5":
// Check if the user provider in use supports passwords retrieval. Access to the users passwords will be required by the CallbackHandler.
if ( !AuthFactory.supportsPasswordRetrieval() )
{
Log.trace( "Cannot support '{}' as the AuthFactory that's in used does not support password retrieval.", mechanism );
it.remove();
}
break;
case "SCRAM-SHA-1":
if ( !AuthFactory.supportsPasswordRetrieval() && !AuthFactory.supportsScram() )
{
Log.trace( "Cannot support '{}' as the AuthFactory that's in used does not support password retrieval nor SCRAM.", mechanism );
it.remove();
}
break;
case "ANONYMOUS":
if ( !JiveGlobals.getBooleanProperty( "xmpp.auth.anonymous" ) )
{
Log.trace( "Cannot support '{}' as it has been disabled by configuration.", mechanism );
it.remove();
}
break;
case "JIVE-SHAREDSECRET":
if ( !JiveSharedSecretSaslServer.isSharedSecretAllowed() )
{
Log.trace( "Cannot support '{}' as it has been disabled by configuration.", mechanism );
it.remove();
}
break;
case "GSSAPI":
final String gssapiConfig = JiveGlobals.getProperty( "sasl.gssapi.config" );
if ( gssapiConfig != null )
{
System.setProperty( "java.security.krb5.debug", JiveGlobals.getProperty( "sasl.gssapi.debug", "false" ) );
System.setProperty( "java.security.auth.login.config", gssapiConfig );
System.setProperty( "javax.security.auth.useSubjectCredsOnly", JiveGlobals.getProperty( "sasl.gssapi.useSubjectCredsOnly", "false" ) );
}
else
{
Log.trace( "Cannot support '{}' as the 'sasl.gssapi.config' property has not been defined.", mechanism );
it.remove();
}
break;
} }
} }
return answer; return answer;
} }
/**
* Returns a collection of mechanism names for which the JVM has an implementation available.
* <p/>
* Note that this need not (and likely will not) correspond with the list of mechanisms that is offered to XMPP
* peer entities, which is provided by #getSupportedMechanisms.
*
* @return a collection of SASL mechanism names (never null, possibly empty)
*/
public static Set<String> getImplementedMechanisms()
{
final Set<String> result = new HashSet<>();
final Enumeration<SaslServerFactory> saslServerFactories = Sasl.getSaslServerFactories();
while ( saslServerFactories.hasMoreElements() )
{
final SaslServerFactory saslServerFactory = saslServerFactories.nextElement();
Collections.addAll( result, saslServerFactory.getMechanismNames( null ) );
}
return result;
}
private static void initMechanisms() private static void initMechanisms()
{ {
// Convert XML based provider setup to Database based
JiveGlobals.migrateProperty("sasl.mechs");
JiveGlobals.migrateProperty("sasl.gssapi.debug");
JiveGlobals.migrateProperty("sasl.gssapi.config");
JiveGlobals.migrateProperty("sasl.gssapi.useSubjectCredsOnly");
final String configuration = JiveGlobals.getProperty("sasl.mechs", "ANONYMOUS,PLAIN,DIGEST-MD5,CRAM-MD5,SCRAM-SHA-1,JIVE-SHAREDSECRET" ); final String configuration = JiveGlobals.getProperty("sasl.mechs", "ANONYMOUS,PLAIN,DIGEST-MD5,CRAM-MD5,SCRAM-SHA-1,JIVE-SHAREDSECRET,GSSAPI" );
final StringTokenizer st = new StringTokenizer(configuration, " ,\t\n\r\f"); final StringTokenizer st = new StringTokenizer(configuration, " ,\t\n\r\f");
mechanisms = new HashSet<>();
while ( st.hasMoreTokens() ) while ( st.hasMoreTokens() )
{ {
final String mech = st.nextToken().toUpperCase(); final String mechanism = st.nextToken().toUpperCase();
try try
{ {
addSupportedMechanism( mech ); addSupportedMechanism( mechanism );
} }
catch ( Exception ex ) catch ( Exception ex )
{ {
Log.warn( "An exception occurred while trying to add support for SASL Mechanism '{}':", mech, ex ); Log.warn( "An exception occurred while trying to add support for SASL Mechanism '{}':", mechanism, ex );
} }
} }
} }
......
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