blob: 1ae667804a443b49466db3ec07a7d93808c1870b [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.qpid.server.security.auth.manager;
import static org.apache.qpid.server.security.auth.AuthenticatedPrincipalTestHelper.assertOnlyContainsWrapped;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.security.Provider;
import java.security.Security;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.callback.CallbackHandler;
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
import javax.security.sasl.SaslServerFactory;
import org.apache.qpid.server.security.auth.AuthenticationResult;
import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus;
import org.apache.qpid.server.security.auth.UsernamePrincipal;
import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser;
import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser;
import org.apache.qpid.test.utils.QpidTestCase;
/**
* Tests the public methods of PrincipalDatabaseAuthenticationManager.
*
*/
public class PrincipalDatabaseAuthenticationManagerTest extends QpidTestCase
{
private static final String MOCK_MECH_NAME = "MOCK-MECH-NAME";
private static final UsernamePrincipal PRINCIPAL = new UsernamePrincipal("guest");
private AuthenticationManager _manager = null; // Class under test
private PrincipalDatabase _principalDatabase;
@Override
public void tearDown() throws Exception
{
if (_manager != null)
{
_manager.close();
}
super.tearDown();
}
private void setupMocks() throws Exception
{
_principalDatabase = mock(PrincipalDatabase.class);
AuthenticationProviderInitialiser _mockMechInitialiser = mock(AuthenticationProviderInitialiser.class);
Map<String, AuthenticationProviderInitialiser> _initialisers = Collections.singletonMap(MOCK_MECH_NAME, _mockMechInitialiser);
when(_principalDatabase.getMechanisms()).thenReturn(_initialisers);
_manager = new PrincipalDatabaseAuthenticationManager(_principalDatabase);
_manager.initialise();
}
private void setupMocksWithInitialiser() throws Exception
{
_principalDatabase = mock(PrincipalDatabase.class);
UsernamePasswordInitialiser usernamePasswordInitialiser = new UsernamePasswordInitialiser()
{
@Override
public Class<? extends SaslServerFactory> getServerFactoryClassForJCARegistration()
{
return MySaslServerFactory.class;
}
@Override
public String getMechanismName()
{
return MOCK_MECH_NAME;
}
};
Map<String,AuthenticationProviderInitialiser> initialisers = new HashMap<String, AuthenticationProviderInitialiser>();
initialisers.put(MOCK_MECH_NAME, usernamePasswordInitialiser);
when(_principalDatabase.getMechanisms()).thenReturn(initialisers);
usernamePasswordInitialiser.initialise(_principalDatabase);
_manager = new PrincipalDatabaseAuthenticationManager(_principalDatabase);
_manager.initialise();
}
/**
* Tests that the PDAM registers SASL mechanisms correctly with the runtime.
*/
public void testRegisteredMechanisms() throws Exception
{
//Ensure we haven't registered anything yet (though this would really indicate a prior test failure!)
Provider qpidProvider = Security.getProvider(AuthenticationManager.PROVIDER_NAME);
assertNull(qpidProvider);
setupMocksWithInitialiser();
assertNotNull(_manager.getMechanisms());
assertEquals(MOCK_MECH_NAME, _manager.getMechanisms());
qpidProvider = Security.getProvider(AuthenticationManager.PROVIDER_NAME);
assertNotNull(qpidProvider);
}
/**
* Tests that the SASL factory method createSaslServer correctly
* returns a non-null implementation.
*/
public void testSaslMechanismCreation() throws Exception
{
setupMocksWithInitialiser();
SaslServer server = _manager.createSaslServer(MOCK_MECH_NAME, "localhost", null);
assertNotNull(server);
// Merely tests the creation of the mechanism. Mechanisms themselves are tested
// by their own tests.
}
/**
* Tests that the authenticate method correctly interprets an
* authentication success.
*
*/
public void testSaslAuthenticationSuccess() throws Exception
{
setupMocks();
SaslServer testServer = createTestSaslServer(true, false);
AuthenticationResult result = _manager.authenticate(testServer, "12345".getBytes());
assertOnlyContainsWrapped(PRINCIPAL, result.getPrincipals());
assertEquals(AuthenticationStatus.SUCCESS, result.getStatus());
}
/**
*
* Tests that the authenticate method correctly interprets an
* authentication not complete.
*
*/
public void testSaslAuthenticationNotCompleted() throws Exception
{
setupMocks();
SaslServer testServer = createTestSaslServer(false, false);
AuthenticationResult result = _manager.authenticate(testServer, "12345".getBytes());
assertEquals("Principals was not expected size", 0, result.getPrincipals().size());
assertEquals(AuthenticationStatus.CONTINUE, result.getStatus());
}
/**
*
* Tests that the authenticate method correctly interprets an
* authentication error.
*
*/
public void testSaslAuthenticationError() throws Exception
{
setupMocks();
SaslServer testServer = createTestSaslServer(false, true);
AuthenticationResult result = _manager.authenticate(testServer, "12345".getBytes());
assertEquals("Principals was not expected size", 0, result.getPrincipals().size());
assertEquals(AuthenticationStatus.ERROR, result.getStatus());
}
public void testNonSaslAuthenticationSuccess() throws Exception
{
setupMocks();
when(_principalDatabase.verifyPassword("guest", "guest".toCharArray())).thenReturn(true);
AuthenticationResult result = _manager.authenticate("guest", "guest");
assertOnlyContainsWrapped(PRINCIPAL, result.getPrincipals());
assertEquals(AuthenticationStatus.SUCCESS, result.getStatus());
}
public void testNonSaslAuthenticationNotCompleted() throws Exception
{
setupMocks();
when(_principalDatabase.verifyPassword("guest", "wrongpassword".toCharArray())).thenReturn(false);
AuthenticationResult result = _manager.authenticate("guest", "wrongpassword");
assertEquals("Principals was not expected size", 0, result.getPrincipals().size());
assertEquals(AuthenticationStatus.CONTINUE, result.getStatus());
}
/**
* Tests the ability to de-register the provider.
*/
public void testClose() throws Exception
{
setupMocksWithInitialiser();
assertEquals(MOCK_MECH_NAME, _manager.getMechanisms());
assertNotNull(Security.getProvider(AuthenticationManager.PROVIDER_NAME));
_manager.close();
// Check provider has been removed.
assertNull(_manager.getMechanisms());
assertNull(Security.getProvider(AuthenticationManager.PROVIDER_NAME));
_manager = null;
}
/**
* Test SASL implementation used to test the authenticate() method.
*/
private SaslServer createTestSaslServer(final boolean complete, final boolean throwSaslException)
{
return new MySaslServer(throwSaslException, complete);
}
public static final class MySaslServer implements SaslServer
{
private final boolean _throwSaslException;
private final boolean _complete;
public MySaslServer()
{
this(false, true);
}
private MySaslServer(boolean throwSaslException, boolean complete)
{
_throwSaslException = throwSaslException;
_complete = complete;
}
public String getMechanismName()
{
return null;
}
public byte[] evaluateResponse(byte[] response) throws SaslException
{
if (_throwSaslException)
{
throw new SaslException("Mocked exception");
}
return null;
}
public boolean isComplete()
{
return _complete;
}
public String getAuthorizationID()
{
return _complete ? "guest" : null;
}
public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException
{
return null;
}
public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException
{
return null;
}
public Object getNegotiatedProperty(String propName)
{
return null;
}
public void dispose() throws SaslException
{
}
}
public static class MySaslServerFactory implements SaslServerFactory
{
@Override
public SaslServer createSaslServer(String mechanism, String protocol,
String serverName, Map<String, ?> props, CallbackHandler cbh)
throws SaslException
{
if (MOCK_MECH_NAME.equals(mechanism))
{
return new MySaslServer();
}
else
{
return null;
}
}
@Override
public String[] getMechanismNames(Map<String, ?> props)
{
return new String[]{MOCK_MECH_NAME};
}
}
}