You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by or...@apache.org on 2020/09/02 19:32:48 UTC
[qpid-broker-j] 01/10: NO-JIRA: Fix Kerberos tests
This is an automated email from the ASF dual-hosted git repository.
orudyy pushed a commit to branch 7.1.x
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git
commit 55bab0d6d226faf9077a6590cecb439f6c2071d8
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Fri Nov 29 13:08:51 2019 +0000
NO-JIRA: Fix Kerberos tests
---
.../manager/KerberosAuthenticationManagerTest.java | 79 +++++----
.../SimpleLDAPAuthenticationManagerTest.java | 17 +-
.../auth/manager/SpnegoAuthenticatorTest.java | 61 +++----
.../qpid/server/test/EmbeddedKdcResource.java | 29 +--
.../apache/qpid/server/test/KerberosUtilities.java | 196 +++++++++++++++++++--
broker-core/src/test/resources/login.ibm.config | 51 ++++++
.../java/org/apache/qpid/test/utils/JvmVendor.java | 25 ++-
.../org/apache/qpid/test/utils/UnitTestBase.java | 18 +-
8 files changed, 338 insertions(+), 138 deletions(-)
diff --git a/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManagerTest.java b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManagerTest.java
index e24d56c..9211710 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManagerTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManagerTest.java
@@ -19,19 +19,22 @@
package org.apache.qpid.server.security.auth.manager;
-import static org.apache.commons.codec.CharEncoding.UTF_8;
import static org.apache.qpid.server.security.auth.manager.KerberosAuthenticationManager.GSSAPI_MECHANISM;
-import static org.hamcrest.Matchers.not;
+import static org.apache.qpid.server.test.KerberosUtilities.ACCEPT_SCOPE;
+import static org.apache.qpid.server.test.KerberosUtilities.CLIENT_PRINCIPAL_FULL_NAME;
+import static org.apache.qpid.server.test.KerberosUtilities.CLIENT_PRINCIPAL_NAME;
+import static org.apache.qpid.server.test.KerberosUtilities.HOST_NAME;
+import static org.apache.qpid.server.test.KerberosUtilities.LOGIN_CONFIG;
+import static org.apache.qpid.server.test.KerberosUtilities.REALM;
+import static org.apache.qpid.server.test.KerberosUtilities.SERVER_PROTOCOL;
+import static org.apache.qpid.server.test.KerberosUtilities.SERVICE_PRINCIPAL_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.File;
-import java.net.URL;
-import java.net.URLDecoder;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Base64;
@@ -45,13 +48,10 @@ import javax.security.auth.login.LoginContext;
import javax.security.sasl.Sasl;
import javax.security.sasl.SaslClient;
-import org.ietf.jgss.GSSException;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.model.AuthenticationProvider;
@@ -62,26 +62,20 @@ import org.apache.qpid.server.security.auth.sasl.SaslNegotiator;
import org.apache.qpid.server.security.auth.sasl.SaslSettings;
import org.apache.qpid.server.test.EmbeddedKdcResource;
import org.apache.qpid.server.test.KerberosUtilities;
-import org.apache.qpid.test.utils.JvmVendor;
+import org.apache.qpid.server.util.StringUtil;
import org.apache.qpid.test.utils.SystemPropertySetter;
import org.apache.qpid.test.utils.UnitTestBase;
public class KerberosAuthenticationManagerTest extends UnitTestBase
{
- private static final Logger LOGGER = LoggerFactory.getLogger(KerberosAuthenticationManagerTest.class);
- private static final String LOGIN_CONFIG = "login.config";
- private static final String REALM = "QPID.ORG";
- private static final String SERVER_NAME = "localhost";
- private static final String SERVER_PROTOCOL = "AMQP";
- private static final String SERVICE_PRINCIPAL_NAME = SERVER_PROTOCOL + "/" + SERVER_NAME;
- private static final String SERVER_PRINCIPAL_FULL_NAME = SERVICE_PRINCIPAL_NAME + "@" + REALM;
- private static final String CLIENT_PRINCIPAL_NAME = "client";
- private static final String CLIENT_PRINCIPAL_FULL_NAME = CLIENT_PRINCIPAL_NAME + "@" + REALM;
private static final KerberosUtilities UTILS = new KerberosUtilities();
@ClassRule
- public static final EmbeddedKdcResource KDC = new EmbeddedKdcResource(REALM);
+ public static final EmbeddedKdcResource KDC = new EmbeddedKdcResource(HOST_NAME,
+ 0,
+ "QpidTestKerberosServer",
+ REALM);
@ClassRule
public static final SystemPropertySetter SYSTEM_PROPERTY_SETTER = new SystemPropertySetter();
@@ -94,21 +88,15 @@ public class KerberosAuthenticationManagerTest extends UnitTestBase
@BeforeClass
public static void createKeyTabs() throws Exception
{
- assumeThat(getJvmVendor(), not(JvmVendor.IBM));
- KDC.createPrincipal("broker.keytab", SERVER_PRINCIPAL_FULL_NAME);
- _clientKeyTabFile = KDC.createPrincipal("client.keytab", CLIENT_PRINCIPAL_FULL_NAME);
- final URL resource = KerberosAuthenticationManagerTest.class.getClassLoader().getResource(LOGIN_CONFIG);
- LOGGER.debug("JAAS config:" + resource);
- assertNotNull(resource);
- SYSTEM_PROPERTY_SETTER.setSystemProperty("java.security.auth.login.config", URLDecoder.decode(resource.getPath(), UTF_8));
- SYSTEM_PROPERTY_SETTER.setSystemProperty("javax.security.auth.useSubjectCredsOnly", "false");
+ UTILS.prepareConfiguration(HOST_NAME, SYSTEM_PROPERTY_SETTER);
+ _clientKeyTabFile = UTILS.prepareKeyTabs(KDC);
}
@Before
public void setUp() throws Exception
{
Map<String, String> context = Collections.singletonMap(KerberosAuthenticationManager.GSSAPI_SPNEGO_CONFIG,
- "com.sun.security.jgss.accept");
+ ACCEPT_SCOPE);
final Map<String, Object> attributes = new HashMap<>();
attributes.put(AuthenticationProvider.NAME, getTestName());
attributes.put(AuthenticationProvider.CONTEXT, context);
@@ -123,7 +111,7 @@ public class KerberosAuthenticationManagerTest extends UnitTestBase
public void testCreateSaslNegotiator() throws Exception
{
final SaslSettings saslSettings = mock(SaslSettings.class);
- when(saslSettings.getLocalFQDN()).thenReturn(SERVER_NAME);
+ when(saslSettings.getLocalFQDN()).thenReturn(HOST_NAME);
final SaslNegotiator negotiator = _kerberosAuthenticationProvider.createSaslNegotiator(GSSAPI_MECHANISM,
saslSettings,
null);
@@ -163,7 +151,7 @@ public class KerberosAuthenticationManagerTest extends UnitTestBase
public void testCreateKerberosAuthenticationProvidersWithNonExistingJaasLoginModule()
{
when(_broker.getChildren(AuthenticationProvider.class)).thenReturn(Collections.emptySet());
- SYSTEM_PROPERTY_SETTER.setSystemProperty("java.security.auth.login.config",
+ SYSTEM_PROPERTY_SETTER.setSystemProperty(LOGIN_CONFIG,
"config.module." + System.nanoTime());
final Map<String, Object> attributes = Collections.singletonMap(AuthenticationProvider.NAME, getTestName());
final KerberosAuthenticationManager kerberosAuthenticationProvider =
@@ -180,10 +168,11 @@ public class KerberosAuthenticationManagerTest extends UnitTestBase
}
@Test
- public void testAuthenticateUsingNegotiationToken() throws GSSException
+ public void testAuthenticateUsingNegotiationToken() throws Exception
{
- final String token =
- Base64.getEncoder().encodeToString(UTILS.buildToken(CLIENT_PRINCIPAL_NAME, SERVICE_PRINCIPAL_NAME));
+ byte[] negotiationTokenBytes =
+ UTILS.buildToken(CLIENT_PRINCIPAL_NAME, _clientKeyTabFile, SERVICE_PRINCIPAL_NAME);
+ final String token = Base64.getEncoder().encodeToString(negotiationTokenBytes);
final String authenticationHeader = SpnegoAuthenticator.NEGOTIATE_PREFIX + token;
final AuthenticationResult result = _kerberosAuthenticationProvider.authenticate(authenticationHeader);
@@ -197,19 +186,30 @@ public class KerberosAuthenticationManagerTest extends UnitTestBase
final LoginContext lc = UTILS.createKerberosKeyTabLoginContext(getTestName(),
CLIENT_PRINCIPAL_FULL_NAME,
_clientKeyTabFile);
+
+ Subject clientSubject = null;
try
{
lc.login();
- final Subject clientSubject = lc.getSubject();
+ clientSubject = lc.getSubject();
+ debug("LoginContext subject {}", clientSubject);
final SaslClient saslClient = createSaslClient(clientSubject);
return performNegotiation(clientSubject, saslClient, negotiator);
}
finally
{
- lc.logout();
+ if (clientSubject != null)
+ {
+ lc.logout();
+ }
}
}
+ private void debug(String message, Object... args)
+ {
+ UTILS.debug(message, args);
+ }
+
private AuthenticationResult performNegotiation(final Subject clientSubject,
final SaslClient saslClient,
final SaslNegotiator negotiator)
@@ -223,6 +223,7 @@ public class KerberosAuthenticationManagerTest extends UnitTestBase
if (!initiated)
{
initiated = true;
+ debug("Sending initial challenge");
response = Subject.doAs(clientSubject, (PrivilegedExceptionAction<byte[]>) () -> {
if (saslClient.hasInitialResponse())
{
@@ -230,19 +231,25 @@ public class KerberosAuthenticationManagerTest extends UnitTestBase
}
return null;
});
+ debug("Initial challenge sent");
}
+ debug("Handling response: {}", StringUtil.toHex(response));
result = negotiator.handleResponse(response);
byte[] challenge = result.getChallenge();
+
if (challenge != null)
{
+ debug("Challenge: {}", StringUtil.toHex(challenge));
response = Subject.doAs(clientSubject,
(PrivilegedExceptionAction<byte[]>) () -> saslClient.evaluateChallenge(
challenge));
}
}
while (result.getStatus() == AuthenticationResult.AuthenticationStatus.CONTINUE);
+
+ debug("Result {}", result.getStatus());
return result;
}
@@ -256,7 +263,7 @@ public class KerberosAuthenticationManagerTest extends UnitTestBase
return Sasl.createSaslClient(new String[]{GSSAPI_MECHANISM},
null,
SERVER_PROTOCOL,
- SERVER_NAME,
+ HOST_NAME,
props,
null);
});
diff --git a/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerTest.java b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerTest.java
index 3f6efa5..ed33947 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerTest.java
@@ -20,7 +20,7 @@ package org.apache.qpid.server.security.auth.manager;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.qpid.server.security.auth.manager.CachingAuthenticationProvider.AUTHENTICATION_CACHE_MAX_SIZE;
-import static org.hamcrest.Matchers.not;
+import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
@@ -31,8 +31,6 @@ import static org.mockito.Mockito.when;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
-import java.net.URL;
-import java.net.URLDecoder;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.security.Principal;
@@ -49,7 +47,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosPrincipal;
-import org.apache.commons.codec.CharEncoding;
import org.apache.directory.api.ldap.model.constants.SupportedSaslMechanisms;
import org.apache.directory.api.ldap.model.entry.DefaultEntry;
import org.apache.directory.api.ldap.model.entry.Entry;
@@ -91,6 +88,7 @@ import org.apache.qpid.server.security.auth.SocketConnectionPrincipal;
import org.apache.qpid.server.security.auth.sasl.SaslNegotiator;
import org.apache.qpid.server.security.auth.sasl.SaslSettings;
import org.apache.qpid.test.utils.JvmVendor;
+import org.apache.qpid.server.test.KerberosUtilities;
import org.apache.qpid.test.utils.SystemPropertySetter;
import org.apache.qpid.test.utils.TestFileUtils;
import org.apache.qpid.test.utils.UnitTestBase;
@@ -147,9 +145,9 @@ public class SimpleLDAPAuthenticationManagerTest extends UnitTestBase
private static final String HOSTNAME = "localhost";
private static final String BROKER_PRINCIPAL = "service/" + HOSTNAME;
private static final String LINE_SEPARATOR = System.lineSeparator();
- private static final String LOGIN_CONFIG = "login.config";
private static final String LOGIN_SCOPE = "ldap-gssapi-bind";
private static final AtomicBoolean KERBEROS_SETUP = new AtomicBoolean();
+ private static final KerberosUtilities UTILS = new KerberosUtilities();
@ClassRule
public static CreateLdapServerRule LDAP = new CreateLdapServerRule();
@@ -400,14 +398,11 @@ public class SimpleLDAPAuthenticationManagerTest extends UnitTestBase
createPrincipal("Service", "LDAP Service", "ldap", UUID.randomUUID().toString(), servicePrincipalName);
}
- private void setUpJaas() throws LdapException, IOException
+ private void setUpJaas() throws Exception
{
createKeyTab(BROKER_PRINCIPAL);
- final URL resource = SimpleLDAPAuthenticationManagerTest.class.getClassLoader().getResource(LOGIN_CONFIG);
- LOGGER.debug("JAAS config:" + resource);
- assertNotNull(resource);
- SYSTEM_PROPERTY_SETTER.setSystemProperty("java.security.auth.login.config", URLDecoder.decode(resource.getPath(), CharEncoding.UTF_8));
- SYSTEM_PROPERTY_SETTER.setSystemProperty("sun.security.krb5.debug", "true");
+
+ UTILS.prepareConfiguration(KerberosUtilities.HOST_NAME, SYSTEM_PROPERTY_SETTER);
}
private String createKrb5Conf(final int port) throws IOException
diff --git a/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SpnegoAuthenticatorTest.java b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SpnegoAuthenticatorTest.java
index d3f8342..bbd65a4 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SpnegoAuthenticatorTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SpnegoAuthenticatorTest.java
@@ -19,52 +19,45 @@
package org.apache.qpid.server.security.auth.manager;
-import static org.apache.commons.codec.CharEncoding.UTF_8;
-import static org.hamcrest.Matchers.not;
+import static org.apache.qpid.server.test.KerberosUtilities.ACCEPT_SCOPE;
+import static org.apache.qpid.server.test.KerberosUtilities.HOST_NAME;
+import static org.apache.qpid.server.test.KerberosUtilities.REALM;
+import static org.apache.qpid.server.test.KerberosUtilities.SERVICE_PRINCIPAL_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import java.net.URL;
-import java.net.URLDecoder;
+import java.io.File;
import java.security.Principal;
import java.util.Base64;
import java.util.Map;
-import org.ietf.jgss.GSSException;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.apache.qpid.server.security.TokenCarryingPrincipal;
import org.apache.qpid.server.security.auth.AuthenticationResult;
import org.apache.qpid.server.test.EmbeddedKdcResource;
import org.apache.qpid.server.test.KerberosUtilities;
-import org.apache.qpid.test.utils.JvmVendor;
import org.apache.qpid.test.utils.SystemPropertySetter;
import org.apache.qpid.test.utils.UnitTestBase;
public class SpnegoAuthenticatorTest extends UnitTestBase
{
- private static final Logger LOGGER = LoggerFactory.getLogger(SpnegoAuthenticatorTest.class);
- private static final String CLIENT_NAME = "client";
- private static final String SERVER_NAME = "AMQP/localhost";
- private static final String ANOTHER_SERVICE = "foo/localhost";
- private static final String REALM = "QPID.ORG";
- private static final String LOGIN_CONFIG = "login.config";
- private static final KerberosUtilities UTILS = new KerberosUtilities();;
+ private static final String ANOTHER_SERVICE = "foo/" + HOST_NAME;
+ private static final String ANOTHER_SERVICE_FULL_NAME = ANOTHER_SERVICE + "@" + REALM;
+ private static final KerberosUtilities UTILS = new KerberosUtilities();
@ClassRule
- public static final EmbeddedKdcResource KDC = new EmbeddedKdcResource(REALM);
+ public static final EmbeddedKdcResource KDC = new EmbeddedKdcResource(HOST_NAME, 0, "QpidTestKerberosServer", REALM);
@ClassRule
public static final SystemPropertySetter SYSTEM_PROPERTY_SETTER = new SystemPropertySetter();
+ private static File _clientKeyTab;
private SpnegoAuthenticator _spnegoAuthenticator;
private KerberosAuthenticationManager _kerberosAuthenticationManager;
@@ -72,31 +65,25 @@ public class SpnegoAuthenticatorTest extends UnitTestBase
@BeforeClass
public static void createKeyTabs() throws Exception
{
- assumeThat(getJvmVendor(), not(JvmVendor.IBM));
- KDC.createPrincipal("broker.keytab", SERVER_NAME + "@" + REALM);
- KDC.createPrincipal("client.keytab", CLIENT_NAME + "@" + REALM);
- KDC.createPrincipal("another.keytab", ANOTHER_SERVICE + "@" + REALM);
- final URL resource = KerberosAuthenticationManagerTest.class.getClassLoader().getResource(LOGIN_CONFIG);
- LOGGER.debug("JAAS config:" + resource);
- assertNotNull(resource);
- SYSTEM_PROPERTY_SETTER.setSystemProperty("java.security.auth.login.config", URLDecoder.decode(resource.getPath(), UTF_8));
- SYSTEM_PROPERTY_SETTER.setSystemProperty("javax.security.auth.useSubjectCredsOnly", "false");
+ KDC.createPrincipal("another.keytab", ANOTHER_SERVICE_FULL_NAME);
+ UTILS.prepareConfiguration(HOST_NAME, SYSTEM_PROPERTY_SETTER);
+ _clientKeyTab = UTILS.prepareKeyTabs(KDC);
}
@Before
public void setUp()
{
_kerberosAuthenticationManager = mock(KerberosAuthenticationManager.class);
- when(_kerberosAuthenticationManager.getSpnegoLoginConfigScope()).thenReturn("com.sun.security.jgss.accept");
+ when(_kerberosAuthenticationManager.getSpnegoLoginConfigScope()).thenReturn(ACCEPT_SCOPE);
when(_kerberosAuthenticationManager.isStripRealmFromPrincipalName()).thenReturn(true);
_spnegoAuthenticator = new SpnegoAuthenticator(_kerberosAuthenticationManager);
}
@Test
- public void testAuthenticate() throws GSSException
+ public void testAuthenticate() throws Exception
{
- final String token = Base64.getEncoder().encodeToString(buildToken(SERVER_NAME));
+ final String token = Base64.getEncoder().encodeToString(buildToken(SERVICE_PRINCIPAL_NAME));
final String authenticationHeader = SpnegoAuthenticator.NEGOTIATE_PREFIX + token;
final AuthenticationResult result = _spnegoAuthenticator.authenticate(authenticationHeader);
@@ -105,7 +92,7 @@ public class SpnegoAuthenticatorTest extends UnitTestBase
assertEquals(AuthenticationResult.AuthenticationStatus.SUCCESS, result.getStatus());
final Principal principal = result.getMainPrincipal();
assertTrue(principal instanceof TokenCarryingPrincipal);
- assertEquals(CLIENT_NAME, principal.getName());
+ assertEquals(KerberosUtilities.CLIENT_PRINCIPAL_NAME, principal.getName());
final Map<String, String> tokens = ((TokenCarryingPrincipal)principal).getTokens();
assertNotNull(tokens);
@@ -121,9 +108,9 @@ public class SpnegoAuthenticatorTest extends UnitTestBase
}
@Test
- public void testAuthenticateNoNegotiatePrefix() throws GSSException
+ public void testAuthenticateNoNegotiatePrefix() throws Exception
{
- final String token = Base64.getEncoder().encodeToString(buildToken(SERVER_NAME));
+ final String token = Base64.getEncoder().encodeToString(buildToken(SERVICE_PRINCIPAL_NAME));
final AuthenticationResult result = _spnegoAuthenticator.authenticate(token);
assertNotNull(result);
assertEquals(AuthenticationResult.AuthenticationStatus.ERROR, result.getStatus());
@@ -148,10 +135,10 @@ public class SpnegoAuthenticatorTest extends UnitTestBase
}
@Test
- public void testAuthenticateWrongConfigName() throws GSSException
+ public void testAuthenticateWrongConfigName() throws Exception
{
when(_kerberosAuthenticationManager.getSpnegoLoginConfigScope()).thenReturn("foo");
- final String token = Base64.getEncoder().encodeToString(buildToken(SERVER_NAME));
+ final String token = Base64.getEncoder().encodeToString(buildToken(SERVICE_PRINCIPAL_NAME));
final String authenticationHeader = SpnegoAuthenticator.NEGOTIATE_PREFIX + token;
final AuthenticationResult result = _spnegoAuthenticator.authenticate(authenticationHeader);
@@ -160,7 +147,7 @@ public class SpnegoAuthenticatorTest extends UnitTestBase
}
@Test
- public void testAuthenticateWrongServer() throws GSSException
+ public void testAuthenticateWrongServer() throws Exception
{
final String token = Base64.getEncoder().encodeToString(buildToken(ANOTHER_SERVICE));
final String authenticationHeader = SpnegoAuthenticator.NEGOTIATE_PREFIX + token;
@@ -170,8 +157,8 @@ public class SpnegoAuthenticatorTest extends UnitTestBase
assertEquals(AuthenticationResult.AuthenticationStatus.ERROR, result.getStatus());
}
- private byte[] buildToken(final String anotherService) throws GSSException
+ private byte[] buildToken(final String anotherService) throws Exception
{
- return UTILS.buildToken(CLIENT_NAME, anotherService);
+ return UTILS.buildToken(KerberosUtilities.CLIENT_PRINCIPAL_NAME, _clientKeyTab, anotherService);
}
}
diff --git a/broker-core/src/test/java/org/apache/qpid/server/test/EmbeddedKdcResource.java b/broker-core/src/test/java/org/apache/qpid/server/test/EmbeddedKdcResource.java
index cda31a8..8224189 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/test/EmbeddedKdcResource.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/test/EmbeddedKdcResource.java
@@ -21,11 +21,11 @@ package org.apache.qpid.server.test;
import java.io.File;
import java.io.IOException;
-import java.net.InetAddress;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
@@ -46,11 +46,6 @@ public class EmbeddedKdcResource extends ExternalResource
private final List<File> _createdFiles = new ArrayList<>();
private volatile File _kdcDirectory;
- public EmbeddedKdcResource(final String realm)
- {
- this(InetAddress.getLoopbackAddress().getCanonicalHostName(), 0, "QpidTestKerberosServer", realm);
- }
-
public EmbeddedKdcResource(final String host, final int port, final String serviceName, final String realm)
{
_realm = realm;
@@ -80,6 +75,7 @@ public class EmbeddedKdcResource extends ExternalResource
_simpleKdcServer.setWorkDir(_kdcDirectory);
_simpleKdcServer.init();
_simpleKdcServer.start();
+ LOGGER.info("SimpleKdcServer started on port {}, realm '{}'", getPort(), getRealm());
}
@Override
@@ -149,7 +145,8 @@ public class EmbeddedKdcResource extends ExternalResource
public File createPrincipal(String keyTabFileName, String... principals)
throws Exception
{
- final File ketTabFile = createFile(keyTabFileName);
+ final Path ketTabPath = Paths.get("target", keyTabFileName);
+ final File ketTabFile = ketTabPath.toFile();
_createdFiles.add(ketTabFile);
createPrincipal(ketTabFile, principals);
return ketTabFile;
@@ -175,22 +172,4 @@ public class EmbeddedKdcResource extends ExternalResource
}
}
- private static File createFile(final String keyTabFile) throws IOException
- {
- final File target = FileSystems.getDefault().getPath("target").toFile();
- final File file = new File(target, keyTabFile);
- if (file.exists())
- {
- if (!file.delete())
- {
- throw new IOException(String.format("Cannot delete existing file '%s'", keyTabFile));
- }
- }
- if (!file.createNewFile())
- {
- throw new IOException(String.format("Cannot create file '%s'", keyTabFile));
- }
- return file;
- }
-
}
diff --git a/broker-core/src/test/java/org/apache/qpid/server/test/KerberosUtilities.java b/broker-core/src/test/java/org/apache/qpid/server/test/KerberosUtilities.java
index 182df06..88fe2db 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/test/KerberosUtilities.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/test/KerberosUtilities.java
@@ -20,8 +20,20 @@
package org.apache.qpid.server.test;
import static java.lang.Boolean.TRUE;
+import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.security.PrivilegedExceptionAction;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -38,6 +50,7 @@ import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
+import com.google.common.io.ByteStreams;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSException;
@@ -47,22 +60,112 @@ import org.ietf.jgss.Oid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.apache.qpid.test.utils.JvmVendor;
+import org.apache.qpid.test.utils.SystemPropertySetter;
+
public class KerberosUtilities
{
+ public static final String REALM = "QPID.ORG";
+ public static final String HOST_NAME = InetAddress.getLoopbackAddress().getCanonicalHostName();
+ public static final String CLIENT_PRINCIPAL_NAME = "client";
+ public static final String CLIENT_PRINCIPAL_FULL_NAME = CLIENT_PRINCIPAL_NAME + "@" + REALM;
+ public static final String SERVER_PROTOCOL = "AMQP";
+ public static final String SERVICE_PRINCIPAL_NAME = SERVER_PROTOCOL + "/" + HOST_NAME;
+ public static final String ACCEPT_SCOPE = isIBM() ? "com.ibm.security.jgss.krb5.accept" : "com.sun.security.jgss.accept";
+ private static final String USE_SUBJECT_CREDS_ONLY = "javax.security.auth.useSubjectCredsOnly";
+ public static final String LOGIN_CONFIG = "java.security.auth.login.config";
+
+ private static final String INITIATE_SCOPE = isIBM() ? "com.ibm.security.jgss.krb5.initiate" : "com.sun.security.jgss.initiate";
private static final Logger LOGGER = LoggerFactory.getLogger(KerberosUtilities.class);
private static final String IBM_LOGIN_MODULE_CLASS = "com.ibm.security.auth.module.Krb5LoginModule";
private static final String SUN_LOGIN_MODULE_CLASS = "com.sun.security.auth.module.Krb5LoginModule";
- public static final String KERBEROS_LOGIN_MODULE_CLASS =
- System.getProperty("java.vendor").contains("IBM") ? IBM_LOGIN_MODULE_CLASS : SUN_LOGIN_MODULE_CLASS;
+ private static final String KERBEROS_LOGIN_MODULE_CLASS = isIBM() ? IBM_LOGIN_MODULE_CLASS : SUN_LOGIN_MODULE_CLASS;
+ private static final String LOGIN_CONFIG_RESOURCE = "login.config";
+ private static final String LOGIN_IBM_CONFIG_RESOURCE = "login.ibm.config";
+ private static final String SERVICE_PRINCIPAL_FULL_NAME = SERVICE_PRINCIPAL_NAME + "@" + REALM;
+ private static final String BROKER_KEYTAB = "broker.keytab";
+ private static final String CLIENT_KEYTAB = "client.keytab";
+
+
+ public File prepareKeyTabs(final EmbeddedKdcResource kdc) throws Exception
+ {
+ final File clientKeyTabFile;
+ kdc.createPrincipal(BROKER_KEYTAB, SERVICE_PRINCIPAL_FULL_NAME);
+ clientKeyTabFile = kdc.createPrincipal(CLIENT_KEYTAB, CLIENT_PRINCIPAL_FULL_NAME);
+ return clientKeyTabFile;
+ }
+
+ public void prepareConfiguration(final String hostName, final SystemPropertySetter systemPropertySetter)
+ throws IOException
+ {
+ final Path loginConfig = transformLoginConfig(hostName);
+ systemPropertySetter.setSystemProperty(LOGIN_CONFIG,
+ URLDecoder.decode(loginConfig.toFile().getAbsolutePath(), UTF_8.name()));
+ systemPropertySetter.setSystemProperty(USE_SUBJECT_CREDS_ONLY, "false");
+ }
+
+ public byte[] buildToken(String clientPrincipalName, File clientKeyTabFile, String targetServerPrincipalName)
+ throws Exception
+ {
+ final LoginContext lc = createKerberosKeyTabLoginContext("test",
+ clientPrincipalName,
+ clientKeyTabFile);
+
+ Subject clientSubject = null;
+ String useSubjectCredsOnly = System.getProperty(USE_SUBJECT_CREDS_ONLY);
+ try
+ {
+ debug("Before login");
+ lc.login();
+ clientSubject = lc.getSubject();
+ debug("LoginContext subject {}", clientSubject);
+ System.setProperty(USE_SUBJECT_CREDS_ONLY, "true");
+ return Subject.doAs(clientSubject,
+ (PrivilegedExceptionAction<byte[]>) () -> buildTokenWithinSubjectWithKerberosTicket(
+ clientPrincipalName,
+ targetServerPrincipalName));
+ }
+ finally
+ {
+ if (useSubjectCredsOnly == null)
+ {
+ System.clearProperty(USE_SUBJECT_CREDS_ONLY);
+ }
+ else
+ {
+ System.setProperty(USE_SUBJECT_CREDS_ONLY, useSubjectCredsOnly);
+ }
+ if (clientSubject != null)
+ {
+ lc.logout();
+ }
+ }
+ }
- public byte[] buildToken(String clientPrincipalName, String targetServerPrincipalName) throws GSSException
+ private byte[] buildTokenWithinSubjectWithKerberosTicket(String clientPrincipalName,
+ String targetServerPrincipalName) throws GSSException
{
+ debug("Building token for client principal '{}' and server principal '{}'",
+ clientPrincipalName,
+ targetServerPrincipalName);
+
final GSSManager manager = GSSManager.getInstance();
final GSSName clientName = manager.createName(clientPrincipalName, GSSName.NT_USER_NAME);
- final GSSCredential credential = manager.createCredential(clientName,
- GSSCredential.DEFAULT_LIFETIME,
- new Oid("1.2.840.113554.1.2.2"),
- GSSCredential.INITIATE_ONLY);
+ final GSSCredential credential;
+ try
+ {
+ credential = manager.createCredential(clientName,
+ GSSCredential.DEFAULT_LIFETIME,
+ new Oid("1.2.840.113554.1.2.2"),
+ GSSCredential.INITIATE_ONLY);
+ }
+ catch (GSSException e)
+ {
+ debug("Failure to create credential for {}", clientName, e);
+ throw e;
+ }
+
+ debug("Client credential '{}'", credential);
final GSSName serverName = manager.createName(targetServerPrincipalName, GSSName.NT_USER_NAME);
final Oid spnegoMechOid = new Oid("1.3.6.1.5.5.2");
@@ -70,11 +173,20 @@ public class KerberosUtilities
spnegoMechOid,
credential,
GSSContext.DEFAULT_LIFETIME);
+
+ debug("Requesting ticket using initiator's credentials");
+
try
{
clientContext.requestCredDeleg(true);
+ debug("Requesting ticket");
return clientContext.initSecContext(new byte[]{}, 0, 0);
}
+ catch (GSSException e)
+ {
+ debug("Failure to request token", e);
+ throw e;
+ }
finally
{
clientContext.dispose();
@@ -166,10 +278,19 @@ public class KerberosUtilities
{
final Map<String, String> options = new HashMap<>();
options.put("principal", principalName);
- options.put("useKeyTab", TRUE.toString());
- options.put("keyTab", keyTabFile.getAbsolutePath());
- options.put("refreshKrb5Config", TRUE.toString());
- options.put("doNotPrompt", TRUE.toString());
+
+ if (isIBM())
+ {
+ options.put("useKeytab", keyTabFile.getAbsolutePath());
+ options.put("credsType", "both");
+ }
+ else
+ {
+ options.put("keyTab", keyTabFile.getAbsolutePath());
+ options.put("useKeyTab", TRUE.toString());
+ options.put("doNotPrompt", TRUE.toString());
+ options.put("refreshKrb5Config", TRUE.toString());
+ }
_entry = new AppConfigurationEntry(KERBEROS_LOGIN_MODULE_CLASS,
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
options);
@@ -186,4 +307,57 @@ public class KerberosUtilities
return new AppConfigurationEntry[0];
}
}
+
+ public void debug(String message, Object... args)
+ {
+ LOGGER.debug(message, args);
+ if (Boolean.TRUE.toString().equalsIgnoreCase(System.getProperty("sun.security.krb5.debug")))
+ {
+ System.out.println(String.format(message.replace("{}", "%s"), args));
+ }
+ }
+
+ private Path transformLoginConfig(String hostName) throws IOException
+ {
+ final String resourceName = isIBM() ? LOGIN_IBM_CONFIG_RESOURCE : LOGIN_CONFIG_RESOURCE;
+ final URL resource = KerberosUtilities.class.getClassLoader().getResource(resourceName);
+ if (resource == null)
+ {
+ throw new IllegalArgumentException(String.format("Unknown resource '%s'", resourceName));
+ }
+ final String config;
+ try (InputStream is = resource.openStream())
+ {
+ config = new String(ByteStreams.toByteArray(is), UTF_8);
+ }
+ catch (IOException e)
+ {
+ throw new IOException(String.format("Failed to load resource '%s'", resource.toExternalForm()), e);
+ }
+ final String newConfig = config.replace("AMQP/localhost", "AMQP/" + hostName)
+ .replace("target/" + BROKER_KEYTAB, toAbsolutePath(BROKER_KEYTAB))
+ .replace("target/" + CLIENT_KEYTAB, toAbsolutePath(CLIENT_KEYTAB));
+
+ final Path file = Paths.get("target", LOGIN_CONFIG_RESOURCE);
+ Files.write(file,
+ newConfig.getBytes(UTF_8),
+ StandardOpenOption.WRITE,
+ StandardOpenOption.CREATE,
+ StandardOpenOption.TRUNCATE_EXISTING);
+ return file.toRealPath(LinkOption.NOFOLLOW_LINKS);
+ }
+
+ private String toAbsolutePath(String fileName)
+ {
+ final Path path = Paths.get("target", fileName)
+ .toAbsolutePath()
+ .normalize();
+ return path.toUri().getPath();
+ }
+
+ private static boolean isIBM()
+ {
+ return JvmVendor.getJvmVendor() == JvmVendor.IBM;
+ }
+
}
diff --git a/broker-core/src/test/resources/login.ibm.config b/broker-core/src/test/resources/login.ibm.config
new file mode 100644
index 0000000..6e85f6e
--- /dev/null
+++ b/broker-core/src/test/resources/login.ibm.config
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+ldap-gssapi-bind {
+ com.ibm.security.auth.module.Krb5LoginModule required
+ credsType="both"
+ principal="service/localhost@QPID.ORG"
+ useKeytab="target/kerberos.keytab";
+};
+
+ldap-gssapi-bind-broken {
+ com.ibm.security.auth.module.Krb5LoginModule required
+ credsType="both"
+ principal="service/localhost@QPID.ORG"
+ useKeytab="target/kerberos-non-existing.keytab";
+};
+
+qpid-broker-j {
+ com.ibm.security.auth.module.Krb5LoginModule required
+ credsType="both"
+ principal="service/localhost@QPID.ORG"
+ useKeytab="target/kerberos.keytab";
+};
+
+com.ibm.security.jgss.krb5.accept {
+ com.ibm.security.auth.module.Krb5LoginModule required
+ credsType="acceptor"
+ principal="AMQP/localhost@QPID.ORG"
+ useKeytab="target/broker.keytab";
+};
+
+com.ibm.security.jgss.krb5.initiate {
+ com.ibm.security.auth.module.Krb5LoginModule required
+ credsType="both"
+ principal="client@QPID.ORG"
+ useKeytab="target/client.keytab";
+};
diff --git a/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/JvmVendor.java b/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/JvmVendor.java
index bd176d7..9ed7c28 100644
--- a/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/JvmVendor.java
+++ b/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/JvmVendor.java
@@ -20,10 +20,33 @@
package org.apache.qpid.test.utils;
+import com.google.common.base.StandardSystemProperty;
+
public enum JvmVendor
{
ORACLE,
IBM,
OPENJDK,
- UNKNOWN
+ UNKNOWN;
+
+ public static JvmVendor getJvmVendor()
+ {
+ final String property = String.valueOf(System.getProperty(StandardSystemProperty.JAVA_VENDOR.key())).toUpperCase();
+ if (property.contains("IBM"))
+ {
+ return JvmVendor.IBM;
+ }
+ else if (property.contains("ORACLE"))
+ {
+ return JvmVendor.ORACLE;
+ }
+ else if (property.contains("OPENJDK"))
+ {
+ return JvmVendor.OPENJDK;
+ }
+ else
+ {
+ return JvmVendor.UNKNOWN;
+ }
+ }
}
diff --git a/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/UnitTestBase.java b/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/UnitTestBase.java
index 4dcfab0..4d71700 100644
--- a/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/UnitTestBase.java
+++ b/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/UnitTestBase.java
@@ -77,23 +77,7 @@ public class UnitTestBase
public static JvmVendor getJvmVendor()
{
- final String property = String.valueOf(System.getProperty(StandardSystemProperty.JAVA_VENDOR.key())).toUpperCase();
- if (property.contains("IBM"))
- {
- return JvmVendor.IBM;
- }
- else if (property.contains("ORACLE"))
- {
- return JvmVendor.ORACLE;
- }
- else if (property.contains("OPENJDK"))
- {
- return JvmVendor.OPENJDK;
- }
- else
- {
- return JvmVendor.UNKNOWN;
- }
+ return JvmVendor.getJvmVendor();
}
public VirtualHostNodeStoreType getVirtualHostNodeStoreType()
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org