| /* |
| * 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.proton.systemtests; |
| |
| import static org.apache.qpid.proton.systemtests.TestLoggingHelper.bold; |
| import static org.junit.Assert.assertArrayEquals; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.fail; |
| |
| import java.nio.charset.StandardCharsets; |
| import java.util.logging.Logger; |
| |
| import org.junit.Test; |
| |
| import org.apache.qpid.proton.Proton; |
| import org.apache.qpid.proton.engine.Sasl; |
| import org.apache.qpid.proton.engine.Sasl.SaslOutcome; |
| |
| public class SaslTest extends EngineTestBase |
| { |
| private static final Logger LOGGER = Logger.getLogger(SaslTest.class.getName()); |
| private static final String TESTMECH1 = "TESTMECH1"; |
| private static final String TESTMECH2 = "TESTMECH2"; |
| private static final byte[] CHALLENGE_BYTES = "challenge-bytes".getBytes(StandardCharsets.UTF_8); |
| private static final byte[] RESPONSE_BYTES = "response-bytes".getBytes(StandardCharsets.UTF_8); |
| private static final byte[] ADDITIONAL_DATA_BYTES = "additional-data-bytes".getBytes(StandardCharsets.UTF_8); |
| |
| @Test |
| public void testSaslHostnamePropagationAndRetrieval() throws Exception |
| { |
| LOGGER.fine(bold("======== About to create transports")); |
| |
| getClient().transport = Proton.transport(); |
| ProtocolTracerEnabler.setProtocolTracer(getClient().transport, TestLoggingHelper.CLIENT_PREFIX); |
| |
| Sasl clientSasl = getClient().transport.sasl(); |
| clientSasl.client(); |
| |
| // Set the server hostname we are connecting to from the client |
| String hostname = "my-remote-host-123"; |
| clientSasl.setRemoteHostname(hostname); |
| |
| // Verify we can't get the hostname on the client |
| try |
| { |
| clientSasl.getHostname(); |
| fail("should have throw IllegalStateException"); |
| } |
| catch (IllegalStateException ise) |
| { |
| // expected |
| } |
| |
| getServer().transport = Proton.transport(); |
| ProtocolTracerEnabler.setProtocolTracer(getServer().transport, " " + TestLoggingHelper.SERVER_PREFIX); |
| |
| // Configure the server to do ANONYMOUS |
| Sasl serverSasl = getServer().transport.sasl(); |
| serverSasl.server(); |
| serverSasl.setMechanisms("ANONYMOUS"); |
| |
| // Verify we can't set the hostname on the server |
| try |
| { |
| serverSasl.setRemoteHostname("some-other-host"); |
| fail("should have throw IllegalStateException"); |
| } |
| catch (IllegalStateException ise) |
| { |
| // expected |
| } |
| |
| assertNull(serverSasl.getHostname()); |
| assertArrayEquals(new String[0], clientSasl.getRemoteMechanisms()); |
| |
| pumpClientToServer(); |
| pumpServerToClient(); |
| |
| // Verify we got the mechs, set the chosen mech, and verify the |
| // server still doesnt know the hostname set/requested by the client |
| assertArrayEquals(new String[] {"ANONYMOUS"} , clientSasl.getRemoteMechanisms()); |
| clientSasl.setMechanisms("ANONYMOUS"); |
| assertNull(serverSasl.getHostname()); |
| |
| pumpClientToServer(); |
| |
| // Verify the server now knows that the client set the hostname field |
| assertEquals(hostname, serverSasl.getHostname()); |
| } |
| |
| /** 5.3.2 SASL Negotiation. */ |
| @Test |
| public void testSaslNegotiation() throws Exception |
| { |
| getClient().transport = Proton.transport(); |
| getServer().transport = Proton.transport(); |
| |
| Sasl clientSasl = getClient().transport.sasl(); |
| clientSasl.client(); |
| assertEquals("Unexpected SASL outcome at client", SaslOutcome.PN_SASL_NONE, clientSasl.getOutcome()); |
| |
| Sasl serverSasl = getServer().transport.sasl(); |
| serverSasl.server(); |
| serverSasl.setMechanisms(TESTMECH1, TESTMECH2); |
| assertEquals("Server should not yet know the remote's chosen mechanism.", |
| 0, |
| serverSasl.getRemoteMechanisms().length); |
| |
| pumpClientToServer(); |
| pumpServerToClient(); |
| |
| assertArrayEquals("Client should now know the server's mechanisms.", |
| new String[]{TESTMECH1, TESTMECH2}, |
| clientSasl.getRemoteMechanisms()); |
| assertEquals("Unexpected SASL outcome at client", SaslOutcome.PN_SASL_NONE, clientSasl.getOutcome()); |
| clientSasl.setMechanisms(TESTMECH1); |
| |
| pumpClientToServer(); |
| |
| assertArrayEquals("Server should now know the client's chosen mechanism.", |
| new String[]{TESTMECH1}, |
| serverSasl.getRemoteMechanisms()); |
| |
| serverSasl.send(CHALLENGE_BYTES, 0, CHALLENGE_BYTES.length); |
| |
| pumpServerToClient(); |
| |
| byte[] clientReceivedChallengeBytes = new byte[clientSasl.pending()]; |
| clientSasl.recv(clientReceivedChallengeBytes, 0, clientReceivedChallengeBytes.length); |
| |
| assertEquals("Unexpected SASL outcome at client", SaslOutcome.PN_SASL_NONE, clientSasl.getOutcome()); |
| assertArrayEquals("Client should now know the server's challenge", |
| CHALLENGE_BYTES, |
| clientReceivedChallengeBytes); |
| |
| clientSasl.send(RESPONSE_BYTES, 0, RESPONSE_BYTES.length); |
| |
| pumpClientToServer(); |
| |
| byte[] serverReceivedResponseBytes = new byte[serverSasl.pending()]; |
| serverSasl.recv(serverReceivedResponseBytes, 0, serverReceivedResponseBytes.length); |
| |
| assertArrayEquals("Server should now know the client's response", |
| RESPONSE_BYTES, |
| serverReceivedResponseBytes); |
| |
| serverSasl.done(SaslOutcome.PN_SASL_OK); |
| pumpServerToClient(); |
| |
| assertEquals("Unexpected SASL outcome at client", SaslOutcome.PN_SASL_OK, clientSasl.getOutcome()); |
| } |
| |
| /** 5.3.2 SASL Negotiation. ...challenge/response step can occur zero or more times*/ |
| @Test |
| public void testOptionalChallengeResponseStepOmitted() throws Exception |
| { |
| getClient().transport = Proton.transport(); |
| getServer().transport = Proton.transport(); |
| |
| Sasl clientSasl = getClient().transport.sasl(); |
| clientSasl.client(); |
| assertEquals("Unexpected SASL outcome at client", SaslOutcome.PN_SASL_NONE, clientSasl.getOutcome()); |
| |
| Sasl serverSasl = getServer().transport.sasl(); |
| serverSasl.server(); |
| serverSasl.setMechanisms(TESTMECH1); |
| assertEquals("Server should not yet know the remote's chosen mechanism.", |
| 0, |
| serverSasl.getRemoteMechanisms().length); |
| |
| pumpClientToServer(); |
| pumpServerToClient(); |
| |
| assertEquals("Unexpected SASL outcome at client", SaslOutcome.PN_SASL_NONE, clientSasl.getOutcome()); |
| clientSasl.setMechanisms(TESTMECH1); |
| |
| pumpClientToServer(); |
| |
| serverSasl.done(SaslOutcome.PN_SASL_OK); |
| pumpServerToClient(); |
| |
| assertEquals("Unexpected SASL outcome at client", SaslOutcome.PN_SASL_OK, clientSasl.getOutcome()); |
| } |
| |
| /** |
| * 5.3.3.5 The additional-data field carries additional data on successful authentication outcome as specified |
| * by the SASL specification [RFC4422]. |
| */ |
| @Test |
| public void testOutcomeAdditionalData() throws Exception |
| { |
| getClient().transport = Proton.transport(); |
| getServer().transport = Proton.transport(); |
| |
| Sasl clientSasl = getClient().transport.sasl(); |
| clientSasl.client(); |
| assertEquals("Unexpected SASL outcome at client", SaslOutcome.PN_SASL_NONE, clientSasl.getOutcome()); |
| |
| Sasl serverSasl = getServer().transport.sasl(); |
| serverSasl.server(); |
| serverSasl.setMechanisms(TESTMECH1); |
| |
| pumpClientToServer(); |
| pumpServerToClient(); |
| |
| assertEquals("Unexpected SASL outcome at client", SaslOutcome.PN_SASL_NONE, clientSasl.getOutcome()); |
| clientSasl.setMechanisms(TESTMECH1); |
| |
| pumpClientToServer(); |
| |
| serverSasl.send(CHALLENGE_BYTES, 0, CHALLENGE_BYTES.length); |
| |
| pumpServerToClient(); |
| |
| byte[] clientReceivedChallengeBytes = new byte[clientSasl.pending()]; |
| clientSasl.recv(clientReceivedChallengeBytes, 0, clientReceivedChallengeBytes.length); |
| |
| assertEquals("Unexpected SASL outcome at client", SaslOutcome.PN_SASL_NONE, clientSasl.getOutcome()); |
| clientSasl.send(RESPONSE_BYTES, 0, RESPONSE_BYTES.length); |
| |
| pumpClientToServer(); |
| |
| byte[] serverReceivedResponseBytes = new byte[serverSasl.pending()]; |
| serverSasl.recv(serverReceivedResponseBytes, 0, serverReceivedResponseBytes.length); |
| |
| serverSasl.send(ADDITIONAL_DATA_BYTES, 0, ADDITIONAL_DATA_BYTES.length); |
| serverSasl.done(SaslOutcome.PN_SASL_OK); |
| pumpServerToClient(); |
| |
| byte[] clientReceivedAdditionalDataBytes = new byte[clientSasl.pending()]; |
| clientSasl.recv(clientReceivedAdditionalDataBytes, 0, clientReceivedAdditionalDataBytes.length); |
| |
| assertEquals("Unexpected SASL outcome at client", SaslOutcome.PN_SASL_OK, clientSasl.getOutcome()); |
| assertArrayEquals("Client should now know the serrver's additional-data", |
| ADDITIONAL_DATA_BYTES, |
| clientReceivedAdditionalDataBytes); |
| } |
| |
| /** |
| * 5.3.3.6 Connection authentication failed due to an unspecified problem with the supplied credentials. |
| */ |
| @Test |
| public void testAuthenticationFails() throws Exception |
| { |
| getClient().transport = Proton.transport(); |
| getServer().transport = Proton.transport(); |
| |
| Sasl clientSasl = getClient().transport.sasl(); |
| clientSasl.client(); |
| assertEquals("Unexpected SASL outcome at client", SaslOutcome.PN_SASL_NONE, clientSasl.getOutcome()); |
| |
| Sasl serverSasl = getServer().transport.sasl(); |
| serverSasl.server(); |
| serverSasl.setMechanisms(TESTMECH1); |
| |
| pumpClientToServer(); |
| pumpServerToClient(); |
| |
| assertEquals("Unexpected SASL outcome at client", SaslOutcome.PN_SASL_NONE, clientSasl.getOutcome()); |
| clientSasl.setMechanisms(TESTMECH1); |
| |
| pumpClientToServer(); |
| |
| serverSasl.done(SaslOutcome.PN_SASL_AUTH); |
| pumpServerToClient(); |
| assertEquals("Unexpected SASL outcome at client", SaslOutcome.PN_SASL_AUTH, clientSasl.getOutcome()); |
| |
| } |
| |
| } |