/* * JBoss, Home of Professional Open Source. * Copyright 2014 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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.wildfly.security.sasl.plain; import static javax.security.sasl.Sasl.POLICY_NOPLAINTEXT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.security.auth.callback.CallbackHandler; import javax.security.sasl.Sasl; import javax.security.sasl.SaslClient; import javax.security.sasl.SaslServer; import javax.security.sasl.SaslServerFactory; import org.junit.Test; import org.wildfly.security.auth.client.AuthenticationConfiguration; import org.wildfly.security.auth.client.AuthenticationContext; import org.wildfly.security.auth.client.ClientUtils; import org.wildfly.security.auth.client.MatchRule; import org.wildfly.security.sasl.test.BaseTestCase; import org.wildfly.security.sasl.test.SaslServerBuilder; /** * Test the server side of the Plain SASL mechanism. * <p/> * (The client side is provided by the JDK so this test case will be testing interoperability * with the JDK supplied implementation) * * @author <a href="mailto:darran.lofthouse@jboss.com">Darran Lofthouse</a> */ public class PlainTest extends BaseTestCase { private static final String PLAIN = "PLAIN"; /* * Mechanism selection tests. */ @Test public void testPolicyIndirect() throws Exception { Map<String, Object> props = new HashMap<String, Object>(); // If we specify PLAIN with no policy restrictions an PlainSaslServer should be returned. SaslServer server = Sasl.createSaslServer(PLAIN, "TestProtocol", "TestServer", props, null); assertEquals(PlainSaslServer.class, server.getClass()); // If we specify no plain text even though we specify PLAIN as the mechanism no server should be // returned. props.put(Sasl.POLICY_NOPLAINTEXT, Boolean.toString(true)); server = Sasl.createSaslServer(PLAIN, "TestProtocol", "TestServer", props, null); assertNull(server); } @Test public void testPolicyDirect() { SaslServerFactory factory = obtainSaslServerFactory(PlainSaslServerFactory.class); assertNotNull("SaslServerFactory not registered", factory); String[] mechanisms; Map<String, Object> props = new HashMap<String, Object>(); // No properties. mechanisms = factory.getMechanismNames(props); assertSingleMechanism(PLAIN, mechanisms); // Request No Plain Text props.put(POLICY_NOPLAINTEXT, Boolean.toString(true)); mechanisms = factory.getMechanismNames(props); assertNoMechanisms(mechanisms); } /* * Normal SASL Client/Server interaction. */ /** * Test a successful exchange using the PLAIN mechanism. */ @Test public void testSuccessfulExchange() throws Exception { SaslServer server = createSaslServer("George", "gpwd".toCharArray()); CallbackHandler clientCallback = createClientCallbackHandler("George", "gpwd".toCharArray()); SaslClient client = Sasl.createSaslClient(new String[]{PLAIN}, "George", "TestProtocol", "TestServer", Collections.<String, Object>emptyMap(), clientCallback); assertFalse(server.isComplete()); assertFalse(client.isComplete()); assertTrue(client.hasInitialResponse()); byte[] message = client.evaluateChallenge(new byte[0]); assertEquals("George\0George\0gpwd",new String(message, StandardCharsets.UTF_8)); server.evaluateResponse(message); assertTrue(server.isComplete()); assertTrue(client.isComplete()); assertEquals("George", server.getAuthorizationID()); } /** * Test that an exchange involving a bad password is correctly rejected. */ @Test public void testBadPassword() throws Exception { SaslServer server = createSaslServer("George", "gpwd".toCharArray()); CallbackHandler clientCallback = createClientCallbackHandler("George", "bad".toCharArray()); SaslClient client = Sasl.createSaslClient(new String[]{PLAIN}, "George", "TestProtocol", "TestServer", Collections.<String, Object>emptyMap(), clientCallback); assertFalse(server.isComplete()); assertFalse(client.isComplete()); assertTrue(client.hasInitialResponse()); byte[] message = client.evaluateChallenge(new byte[0]); assertEquals("George\0George\0bad",new String(message, StandardCharsets.UTF_8)); try { server.evaluateResponse(message); fail("Expection exception not thrown."); } catch (IOException e) {} // server is complete even if an exception is thrown. Ref: JDK assertTrue(server.isComplete()); assertTrue(client.isComplete()); } /** * Test that an exchange involving a bad username is correctly rejected. */ @Test public void testBadUsername() throws Exception { SaslServer server = createSaslServer("Borris", "gpwd".toCharArray()); CallbackHandler clientCallback = createClientCallbackHandler("George", "gpwd".toCharArray()); SaslClient client = Sasl.createSaslClient(new String[]{PLAIN}, "George", "TestProtocol", "TestServer", Collections.<String, Object>emptyMap(), clientCallback); assertFalse(server.isComplete()); assertFalse(client.isComplete()); assertTrue(client.hasInitialResponse()); byte[] message = client.evaluateChallenge(new byte[0]); assertEquals("George\0George\0gpwd", new String(message, StandardCharsets.UTF_8)); try { server.evaluateResponse(message); fail("Expection exception not thrown."); } catch (IOException e) {} // server is complete even if an exception is thrown. Ref: JDK assertTrue(server.isComplete()); assertTrue(client.isComplete()); } /** * Test a successful exchange using the PLAIN mechanism where no Authorization ID is specified. */ @Test public void testSuccessfulExchange_NoAuthorization() throws Exception { SaslServer server = createSaslServer("George", "gpwd".toCharArray()); CallbackHandler clientCallback = createClientCallbackHandler("George", "gpwd".toCharArray()); SaslClient client = Sasl.createSaslClient(new String[]{PLAIN}, null, "TestProtocol", "TestServer", Collections.<String, Object>emptyMap(), clientCallback); assertFalse(server.isComplete()); assertFalse(client.isComplete()); assertTrue(client.hasInitialResponse()); byte[] message = client.evaluateChallenge(new byte[0]); assertEquals("\0George\0gpwd",new String(message, StandardCharsets.UTF_8)); server.evaluateResponse(message); assertTrue(server.isComplete()); assertTrue(client.isComplete()); assertEquals("George", server.getAuthorizationID()); } /** * Test that an exchange involving a disallowed authorization ID is correctly rejected. */ @Test public void testSuccessfulExchange_DifferentAuthorizationID() throws Exception { SaslServer server = createSaslServer("George", "gpwd".toCharArray()); CallbackHandler clientCallback = createClientCallbackHandler("George", "gpwd".toCharArray()); SaslClient client = Sasl.createSaslClient(new String[]{PLAIN}, "Borris", "TestProtocol", "TestServer", Collections.<String, Object>emptyMap(), clientCallback); assertFalse(server.isComplete()); assertFalse(client.isComplete()); assertTrue(client.hasInitialResponse()); byte[] message = client.evaluateChallenge(new byte[0]); assertEquals("Borris\0George\0gpwd",new String(message, StandardCharsets.UTF_8)); try { server.evaluateResponse(message); fail("Exception not thrown."); } catch (IOException e) { } // server is complete even if an exception is thrown. Ref: JDK assertTrue(server.isComplete()); assertTrue(client.isComplete()); } /** * Test a successful exchange using minimal maximum allowed length of credentials - 255B */ @Test public void testMaximumLength() throws Exception { SaslServer server = createSaslServer("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb".toCharArray()); CallbackHandler clientCallback = createClientCallbackHandler("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb".toCharArray()); SaslClient client = Sasl.createSaslClient(new String[]{PLAIN}, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "TestProtocol", "TestServer", Collections.<String, Object>emptyMap(), clientCallback); assertFalse(server.isComplete()); assertFalse(client.isComplete()); assertTrue(client.hasInitialResponse()); byte[] message = client.evaluateChallenge(new byte[0]); assertEquals("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\0bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",new String(message, StandardCharsets.UTF_8)); server.evaluateResponse(message); assertTrue(server.isComplete()); assertTrue(client.isComplete()); assertEquals("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", server.getAuthorizationID()); } private SaslServer createSaslServer(final String expectedUsername, final char[] expectedPassword) throws Exception { return new SaslServerBuilder(PlainSaslServerFactory.class, PLAIN) .setUserName(expectedUsername) .setPassword(expectedPassword) .build(); } private CallbackHandler createClientCallbackHandler(final String username, final char[] password) throws Exception { final AuthenticationContext context = AuthenticationContext.empty() .with( MatchRule.ALL, AuthenticationConfiguration.EMPTY .useName(username) .usePassword(password) .allowSaslMechanisms(PLAIN)); return ClientUtils.getCallbackHandler(new URI("doesnot://matter?"), context); } }