Skip to content

Commit

Permalink
Fixed connection refused message
Browse files Browse the repository at this point in the history
Throws proper error when connection refused.
Also fixed flaky test that highlighted problem. Changed testname to
properly reflect what is being tested.
  • Loading branch information
OliviaYtterbrink committed Apr 28, 2017
1 parent 684fd26 commit dd15215
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 13 deletions.
Expand Up @@ -31,6 +31,7 @@
import org.neo4j.bolt.v1.runtime.cypher.StatementProcessor;
import org.neo4j.bolt.v1.runtime.spi.BoltResult;
import org.neo4j.function.ThrowingConsumer;
import org.neo4j.graphdb.security.AuthProviderFailedException;
import org.neo4j.graphdb.security.AuthorizationExpiredException;
import org.neo4j.graphdb.security.AuthProviderTimeoutException;
import org.neo4j.kernel.api.bolt.ManagedBoltStateMachine;
Expand Down Expand Up @@ -364,7 +365,7 @@ public State init( BoltStateMachine machine, String userAgent,
}
return READY;
}
catch ( AuthenticationException | AuthProviderTimeoutException e )
catch ( AuthenticationException | AuthProviderTimeoutException | AuthProviderFailedException e)
{
fail( machine, Neo4jError.fatalFrom( e.status(), e.getMessage() ) );
throw new BoltConnectionAuthFatality( e.getMessage() );
Expand Down
Expand Up @@ -27,14 +27,14 @@
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.ldap.DefaultLdapRealm;
import org.apache.shiro.realm.ldap.JndiLdapContextFactory;
import org.apache.shiro.realm.ldap.JndiLdapRealm;
import org.apache.shiro.realm.ldap.LdapContextFactory;
import org.apache.shiro.realm.ldap.LdapUtils;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.CollectionUtils;

import java.io.IOException;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -59,9 +59,9 @@
import javax.naming.ldap.StartTlsRequest;
import javax.naming.ldap.StartTlsResponse;

import org.neo4j.graphdb.security.AuthorizationExpiredException;
import org.neo4j.graphdb.security.AuthProviderFailedException;
import org.neo4j.graphdb.security.AuthProviderTimeoutException;
import org.neo4j.graphdb.security.AuthorizationExpiredException;
import org.neo4j.kernel.api.security.AuthToken;
import org.neo4j.kernel.api.security.AuthenticationResult;
import org.neo4j.kernel.api.security.exception.InvalidAuthTokenException;
Expand All @@ -74,7 +74,7 @@
/**
* Shiro realm for LDAP based on configuration settings
*/
public class LdapRealm extends JndiLdapRealm implements RealmLifecycle, ShiroAuthorizationInfoProvider
public class LdapRealm extends DefaultLdapRealm implements RealmLifecycle, ShiroAuthorizationInfoProvider
{
private static final String GROUP_DELIMITER = ";";
private static final String KEY_VALUE_DELIMITER = "=";
Expand All @@ -89,6 +89,7 @@ public class LdapRealm extends JndiLdapRealm implements RealmLifecycle, ShiroAut
public static final String LDAP_CONNECTION_TIMEOUT_CLIENT_MESSAGE = "LDAP connection timed out.";
public static final String LDAP_READ_TIMEOUT_CLIENT_MESSAGE = "LDAP response timed out.";
public static final String LDAP_AUTHORIZATION_FAILURE_CLIENT_MESSAGE = "LDAP authorization request failed.";
public static final String LDAP_CONNECTION_REFUSED_CLIENT_MESSAGE = "LDAP connection refused.";

private Boolean authenticationEnabled;
private Boolean authorizationEnabled;
Expand Down Expand Up @@ -167,6 +168,11 @@ else if ( isExceptionAnLdapReadTimeout( e ) )
securityLog.error( withRealm( "LDAP response from %s timed out.", serverString ) );
throw new AuthProviderTimeoutException( LDAP_READ_TIMEOUT_CLIENT_MESSAGE, e );
}
else if ( isExceptionConnectionRefused( e ) )
{
securityLog.error( withRealm( "LDAP connection to %s was refused.", serverString ) );
throw new AuthProviderFailedException( LDAP_CONNECTION_REFUSED_CLIENT_MESSAGE, e );
}
// This exception will be caught and rethrown by Shiro, and then by us, so we do not need to wrap it here
throw e;
}
Expand Down Expand Up @@ -400,6 +406,12 @@ private boolean isExceptionAnLdapConnectionTimeout( Exception e )
JNDI_LDAP_CONNECTION_TIMEOUT_MESSAGE_PART ) );
}

private boolean isExceptionConnectionRefused( Exception e )
{
return e instanceof CommunicationException &&
((CommunicationException) e).getRootCause() instanceof ConnectException;
}

private boolean isAuthorizationExceptionAnLdapReadTimeout( AuthorizationException e )
{
// Shiro's doGetAuthorizationInfo() wraps a NamingException in an AuthorizationException
Expand Down
Expand Up @@ -43,6 +43,7 @@
import java.util.List;
import java.util.Map;

import org.neo4j.graphdb.security.AuthProviderFailedException;
import org.neo4j.graphdb.security.AuthProviderTimeoutException;
import org.neo4j.kernel.api.security.AuthenticationResult;
import org.neo4j.kernel.api.security.SecurityContext;
Expand Down Expand Up @@ -131,6 +132,12 @@ public EnterpriseSecurityContext login( Map<String,Object> authToken ) throws In
escape( token.getPrincipal().toString() ) );
throw new AuthProviderTimeoutException( e.getCause().getMessage(), e.getCause() );
}
else if ( e.getCause() != null && e.getCause() instanceof AuthProviderFailedException )
{
securityLog.error( "[%s]: failed to log in: auth server connection refused",
escape( token.getPrincipal().toString() ) );
throw new AuthProviderFailedException( e.getCause().getMessage(), e.getCause() );
}
securityContext = new StandardEnterpriseSecurityContext( this,
new ShiroSubject( securityManager, AuthenticationResult.FAILURE ) );
securityLog.error( "[%s]: failed to log in: invalid principal or credentials",
Expand Down
Expand Up @@ -78,7 +78,7 @@
import static org.neo4j.bolt.v1.transport.integration.TransportTestUtil.eventuallyDisconnects;
import static org.neo4j.bolt.v1.transport.integration.TransportTestUtil.eventuallyReceives;
import static org.neo4j.server.security.enterprise.auth.LdapRealm.LDAP_AUTHORIZATION_FAILURE_CLIENT_MESSAGE;
import static org.neo4j.server.security.enterprise.auth.LdapRealm.LDAP_CONNECTION_TIMEOUT_CLIENT_MESSAGE;
import static org.neo4j.server.security.enterprise.auth.LdapRealm.LDAP_CONNECTION_REFUSED_CLIENT_MESSAGE;
import static org.neo4j.server.security.enterprise.auth.LdapRealm.LDAP_READ_TIMEOUT_CLIENT_MESSAGE;

interface TimeoutTests { /* Category marker */ };
Expand Down Expand Up @@ -564,16 +564,14 @@ public void shouldBeAbleToUseProcedureAllowedAnnotationWithLdapGroupToRoleMappin
}

@Test
public void shouldTimeoutIfInvalidLdapServer() throws Throwable
public void shouldFailIfInvalidLdapServer() throws Throwable
{
// When
restartNeo4jServerWithOverriddenSettings( ldapOnlyAuthSettings.andThen( settings -> {
settings.put( SecuritySettings.ldap_server, "ldap://198.51.100.9" ); // An IP in the TEST-NET-2 range
settings.put( SecuritySettings.ldap_connection_timeout, "1s" );
} ) );
restartNeo4jServerWithOverriddenSettings( ldapOnlyAuthSettings.andThen(
settings -> settings.put( SecuritySettings.ldap_server, "ldap://127.0.0.1" ) ) );

assertConnectionTimeout( authToken( "neo", "abc123", null ),
LDAP_CONNECTION_TIMEOUT_CLIENT_MESSAGE );
assertConnectionRefused( authToken( "neo", "abc123", null ),
LDAP_CONNECTION_REFUSED_CLIENT_MESSAGE );

assertThat( client, eventuallyDisconnects() );
}
Expand Down Expand Up @@ -1041,6 +1039,19 @@ private void assertConnectionTimeout( Map<String,Object> authToken, String messa
assertThat( client, eventuallyDisconnects() );
}

private void assertConnectionRefused( Map<String,Object> authToken, String message ) throws Exception
{
client.connect( address )
.send( TransportTestUtil.acceptedVersions( 1, 0, 0, 0 ) )
.send( TransportTestUtil.chunk(
init( "TestClient/1.1", authToken ) ) );

assertThat( client, eventuallyReceives( new byte[]{0, 0, 0, 1} ) );
assertThat( client, eventuallyReceives( msgFailure( Status.Security.AuthProviderFailed, message ) ) );

assertThat( client, eventuallyDisconnects() );
}

private void testClearAuthCache() throws Exception
{
assertAuth( "neo4j", "abc123" );
Expand Down

0 comments on commit dd15215

Please sign in to comment.