/*
* Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved.
*
* 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 com.hazelcast.client.protocol;
import com.hazelcast.client.ClientTypes;
import com.hazelcast.client.impl.protocol.ClientMessage;
import com.hazelcast.client.impl.protocol.codec.ClientAuthenticationCodec;
import com.hazelcast.client.impl.protocol.util.ClientProtocolBuffer;
import com.hazelcast.config.Config;
import com.hazelcast.config.GroupConfig;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.instance.BuildInfoProvider;
import com.hazelcast.internal.serialization.InternalSerializationService;
import com.hazelcast.nio.Address;
import com.hazelcast.test.HazelcastSerialClassRunner;
import com.hazelcast.test.annotation.QuickTest;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.UUID;
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;
/**
* Server side client protocol tests
*/
@RunWith(HazelcastSerialClassRunner.class)
@Category(QuickTest.class)
public class RawProtocolAuthenticationTest {
static HazelcastInstance server;
private SocketChannel channel;
@BeforeClass
public static void init() {
Config config = new Config();
config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(false);
server = Hazelcast.newHazelcastInstance();
}
@AfterClass
public static void destroy() {
Hazelcast.shutdownAll();
}
@Before
public void setUp()
throws IOException, InterruptedException {
final InetSocketAddress socketAddress = server.getCluster().getLocalMember().getSocketAddress();
final Address address = new Address(socketAddress);
channel = SocketChannel.open();
channel.socket().connect(address.getInetSocketAddress());
channel.configureBlocking(true);
while (!channel.isConnected()) {
Thread.sleep(10);
}
}
@After
public void tearDown()
throws Exception {
channel.close();
}
@Test
public void testAuthenticateWithUsernameAndPassword()
throws IOException, InterruptedException {
final ByteBuffer initData = ByteBuffer.wrap("CB2".getBytes());
channel.write(initData);
String username = GroupConfig.DEFAULT_GROUP_NAME;
String pass = GroupConfig.DEFAULT_GROUP_PASSWORD;
final ClientMessage authMessage = ClientAuthenticationCodec.encodeRequest(username, pass, null, null,
true, ClientTypes.JAVA, InternalSerializationService.VERSION_1, BuildInfoProvider.BUILD_INFO.getVersion());
authMessage.setCorrelationId(1).addFlag(ClientMessage.BEGIN_AND_END_FLAGS);
final ClientProtocolBuffer byteBuffer = authMessage.buffer();
channel.write(ByteBuffer.wrap(byteBuffer.byteArray(), 0, authMessage.getFrameLength()));
ClientMessage clientMessage = readMessageFromChannel();
assertTrue(clientMessage.isComplete());
ClientMessage cmResult = ClientMessage.createForDecode(clientMessage.buffer(), 0);
ClientAuthenticationCodec.ResponseParameters resultParameters = ClientAuthenticationCodec.decodeResponse(cmResult);
assertEquals(cmResult.getCorrelationId(), 1);
assertEquals(resultParameters.status, 0);
assertEquals(resultParameters.serializationVersion, 1);
assertEquals(resultParameters.ownerUuid, server.getCluster().getLocalMember().getUuid());
assertNotNull(UUID.fromString(resultParameters.uuid));
assertEquals(server.getCluster().getLocalMember().getAddress(), resultParameters.address);
}
@Test
public void testAuthenticateWithUsernameAndPassword_with_Invalid_Credentials()
throws IOException, InterruptedException {
final ByteBuffer initData = ByteBuffer.wrap("CB2".getBytes());
channel.write(initData);
String username = GroupConfig.DEFAULT_GROUP_NAME;
String pass = "TheInvalidPassword";
final ClientMessage authMessage = ClientAuthenticationCodec
.encodeRequest(username, pass, null, null, true, ClientTypes.JAVA, InternalSerializationService.VERSION_1,
BuildInfoProvider.BUILD_INFO.getVersion());
authMessage.setCorrelationId(1).addFlag(ClientMessage.BEGIN_AND_END_FLAGS);
final ClientProtocolBuffer byteBuffer = authMessage.buffer();
channel.write(ByteBuffer.wrap(byteBuffer.byteArray(), 0, authMessage.getFrameLength()));
ClientMessage clientMessage = readMessageFromChannel();
assertTrue(clientMessage.isComplete());
ClientMessage cmResult = ClientMessage.createForDecode(clientMessage.buffer(), 0);
ClientAuthenticationCodec.ResponseParameters resultParameters = ClientAuthenticationCodec.decodeResponse(cmResult);
assertEquals(cmResult.getCorrelationId(), 1);
assertEquals(resultParameters.status, 1);
assertEquals(resultParameters.serializationVersion, 1);
assertNull(resultParameters.ownerUuid);
assertNull(resultParameters.uuid);
assertNull(resultParameters.address);
}
@Test
public void testAuthenticateWithUsernameAndPassword_with_Invalid_SerializationVersion()
throws IOException, InterruptedException {
final ByteBuffer initData = ByteBuffer.wrap("CB2".getBytes());
channel.write(initData);
String username = GroupConfig.DEFAULT_GROUP_NAME;
String pass = GroupConfig.DEFAULT_GROUP_PASSWORD;
final ClientMessage authMessage = ClientAuthenticationCodec
.encodeRequest(username, pass, null, null, true, ClientTypes.JAVA, (byte) 0,
BuildInfoProvider.BUILD_INFO.getVersion());
authMessage.setCorrelationId(1).addFlag(ClientMessage.BEGIN_AND_END_FLAGS);
final ClientProtocolBuffer byteBuffer = authMessage.buffer();
channel.write(ByteBuffer.wrap(byteBuffer.byteArray(), 0, authMessage.getFrameLength()));
ClientMessage clientMessage = readMessageFromChannel();
assertTrue(clientMessage.isComplete());
ClientMessage cmResult = ClientMessage.createForDecode(clientMessage.buffer(), 0);
ClientAuthenticationCodec.ResponseParameters resultParameters = ClientAuthenticationCodec.decodeResponse(cmResult);
assertEquals(cmResult.getCorrelationId(), 1);
assertEquals(resultParameters.status, 2);
assertEquals(resultParameters.serializationVersion, 1);
assertNull(resultParameters.ownerUuid);
assertNull(resultParameters.uuid);
assertNull(resultParameters.address);
}
@Test
public void testAuthenticateWithUsernameAndPassword_with_Invalid_MessageSize()
throws IOException, InterruptedException {
final ByteBuffer initData = ByteBuffer.wrap("CB2".getBytes());
channel.write(initData);
String username = GroupConfig.DEFAULT_GROUP_NAME;
String pass = GroupConfig.DEFAULT_GROUP_PASSWORD;
final ClientMessage authMessage = ClientAuthenticationCodec
.encodeRequest(username, pass, null, null, true, ClientTypes.JAVA, (byte) 0,
BuildInfoProvider.BUILD_INFO.getVersion());
authMessage.setCorrelationId(1).addFlag(ClientMessage.BEGIN_AND_END_FLAGS);
//set invalid message size
authMessage.setFrameLength(ClientMessage.HEADER_SIZE - 1);
final ClientProtocolBuffer byteBuffer = authMessage.buffer();
channel.write(ByteBuffer.wrap(byteBuffer.byteArray(), 0, authMessage.getFrameLength()));
ClientMessage clientMessage = readMessageFromChannel();
assertFalse(clientMessage.isComplete());
}
private ClientMessage readMessageFromChannel()
throws IOException {
final ByteBuffer socketBuffer = ByteBuffer.allocate(4096);
ClientMessage clientMessage = ClientMessage.create();
do {
int read = channel.read(socketBuffer);
if (read <= 0) {
if (read == -1) {
break;
}
continue;
}
socketBuffer.flip();
clientMessage.readFrom(socketBuffer);
if (socketBuffer.hasRemaining()) {
socketBuffer.compact();
} else {
socketBuffer.clear();
}
} while (!clientMessage.isComplete());
return clientMessage;
}
}