org.jivesoftware.openfire.sasl.SaslServerFactoryImpl Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2004-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.sasl;
import org.jivesoftware.openfire.session.LocalClientSession;
import org.jivesoftware.openfire.session.LocalIncomingServerSession;
import org.jivesoftware.openfire.session.LocalSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.security.auth.callback.CallbackHandler;
import javax.security.sasl.Sasl;
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
import javax.security.sasl.SaslServerFactory;
/**
* Server Factory for supported mechanisms.
*
* @author Jay Kline
*/
public class SaslServerFactoryImpl implements SaslServerFactory
{
private final static Logger Log = LoggerFactory.getLogger( SaslServerFactoryImpl.class );
/**
* All mechanisms provided by this factory.
*/
private final Set allMechanisms;
public SaslServerFactoryImpl()
{
allMechanisms = new HashSet<>();
allMechanisms.add( new Mechanism( "ANONYMOUS", true, true ) );
allMechanisms.add( new Mechanism( "PLAIN", false, true ) );
allMechanisms.add( new Mechanism( "SCRAM-SHA-1", false, false ) );
allMechanisms.add( new Mechanism( "JIVE-SHAREDSECRET", true, false ) );
allMechanisms.add( new Mechanism( "EXTERNAL", false, false ) );
}
@Override
public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props, CallbackHandler cbh) throws SaslException
{
if ( !Arrays.asList( getMechanismNames( props )).contains( mechanism ) )
{
Log.debug( "This implementation is unable to create a SaslServer instance for the {} mechanism using the provided properties.", mechanism );
return null;
}
switch ( mechanism.toUpperCase() )
{
case "PLAIN":
if ( cbh == null )
{
Log.debug( "Unable to instantiate {} SaslServer: A callbackHandler with support for Password, Name, and AuthorizeCallback required.", mechanism );
return null;
}
return new SaslServerPlainImpl( protocol, serverName, props, cbh );
case "SCRAM-SHA-1":
return new ScramSha1SaslServer();
case "ANONYMOUS":
if ( !props.containsKey( LocalSession.class.getCanonicalName() ) )
{
Log.debug( "Unable to instantiate {} SaslServer: Provided properties do not contain a LocalSession instance.", mechanism );
return null;
}
else
{
final LocalSession session = (LocalSession) props.get( LocalSession.class.getCanonicalName() );
return new AnonymousSaslServer( session );
}
case "EXTERNAL":
if ( !props.containsKey( LocalSession.class.getCanonicalName() ) )
{
Log.debug( "Unable to instantiate {} SaslServer: Provided properties do not contain a LocalSession instance.", mechanism );
return null;
}
else
{
final Object session = props.get( LocalSession.class.getCanonicalName() );
if ( session instanceof LocalClientSession )
{
return new ExternalClientSaslServer( (LocalClientSession) session );
}
if ( session instanceof LocalIncomingServerSession )
{
return new ExternalServerSaslServer( (LocalIncomingServerSession) session );
}
Log.debug( "Unable to instantiate {} Sasl Server: Provided properties contains neither LocalClientSession nor LocalIncomingServerSession instance.", mechanism );
return null;
}
case JiveSharedSecretSaslServer.NAME:
return new JiveSharedSecretSaslServer();
default:
throw new IllegalStateException(); // Fail fast - this should not be possible, as the first check in this method already verifies wether the mechanism is supported.
}
}
@Override
public String[] getMechanismNames( Map props )
{
final Set result = new HashSet<>();
for ( final Mechanism mechanism : allMechanisms )
{
if ( props != null )
{
if ( mechanism.allowsAnonymous && props.containsKey( Sasl.POLICY_NOANONYMOUS ) && Boolean.parseBoolean( (String) props.get( Sasl.POLICY_NOANONYMOUS ) ) )
{
// Do not include a mechanism that allows anonymous authentication when the 'no anonymous' policy is set.
continue;
}
if ( mechanism.isPlaintext && props.containsKey( Sasl.POLICY_NOPLAINTEXT ) && Boolean.parseBoolean( (String) props.get( Sasl.POLICY_NOPLAINTEXT ) ) )
{
// Do not include a mechanism that is susceptible to simple plain passive attacks when the 'no plaintext' policy is set.
continue;
}
}
// Mechanism passed all filters. It should be part of the result.
result.add( mechanism.name );
}
return result.toArray( new String[ result.size() ] );
}
private static class Mechanism
{
final String name;
final boolean allowsAnonymous;
final boolean isPlaintext;
private Mechanism( String name, boolean allowsAnonymous, boolean isPlaintext )
{
this.name = name;
this.allowsAnonymous = allowsAnonymous;
this.isPlaintext = isPlaintext;
}
}
}