MQTT encode doesn't complain if password is set but username not

Motivation:

The MQTT decoder should raise an exception trying to build a CONNECT packet where password field is set but not the username one (as by MQTT 3.1/3.1.1 spec).

Modification:

Throw exception if password field is set but not the username

Result:

Fixes [#7205].
This commit is contained in:
Paolo Patierno 2017-09-13 17:47:30 +02:00 committed by Norman Maurer
parent 426938307d
commit 901c66fa81
3 changed files with 25 additions and 4 deletions

View File

@ -20,6 +20,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.EmptyArrays;
@ -102,6 +103,11 @@ public final class MqttEncoder extends MessageToMessageEncoder<MqttMessage> {
MqttVersion mqttVersion = MqttVersion.fromProtocolNameAndLevel(variableHeader.name(),
(byte) variableHeader.version());
// as MQTT 3.1 & 3.1.1 spec, If the User Name Flag is set to 0, the Password Flag MUST be set to 0
if (!variableHeader.hasUserName() && variableHeader.hasPassword()) {
throw new DecoderException("Without a username, the password MUST be not set");
}
// Client id
String clientIdentifier = payload.clientIdentifier();
if (!isValidClientId(mqttVersion, clientIdentifier)) {

View File

@ -150,7 +150,7 @@ public final class MqttMessageBuilders {
}
public ConnectBuilder username(String username) {
this.hasUser = true;
this.hasUser = username != null;
this.username = username;
return this;
}
@ -165,7 +165,7 @@ public final class MqttMessageBuilders {
}
public ConnectBuilder password(byte[] password) {
this.hasPassword = true;
this.hasPassword = password != null;
this.password = password;
return this;
}

View File

@ -120,6 +120,17 @@ public class MqttCodecTest {
}
}
@Test
public void testConnectMessageNoPassword() throws Exception {
final MqttConnectMessage message = createConnectMessage(MqttVersion.MQTT_3_1_1, null, PASSWORD);
try {
ByteBuf byteBuf = MqttEncoder.doEncode(ALLOCATOR, message);
} catch (Exception cause) {
assertTrue(cause instanceof DecoderException);
}
}
@Test
public void testConnAckMessage() throws Exception {
final MqttConnAckMessage message = createConnAckMessage();
@ -313,11 +324,15 @@ public class MqttCodecTest {
}
private static MqttConnectMessage createConnectMessage(MqttVersion mqttVersion) {
return createConnectMessage(mqttVersion, USER_NAME, PASSWORD);
}
private static MqttConnectMessage createConnectMessage(MqttVersion mqttVersion, String username, String password) {
return MqttMessageBuilders.connect()
.clientId(CLIENT_ID)
.protocolVersion(mqttVersion)
.username(USER_NAME)
.password(PASSWORD)
.username(username)
.password(password)
.willRetain(true)
.willQoS(MqttQoS.AT_LEAST_ONCE)
.willFlag(true)