Skip to content

Commit

Permalink
CONNECT username and password need json encoding (#1168)
Browse files Browse the repository at this point in the history
  • Loading branch information
scottf authored Jun 27, 2024
1 parent f5417e7 commit fd76e1d
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 47 deletions.
24 changes: 12 additions & 12 deletions src/main/java/io/nats/client/Options.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

import static io.nats.client.support.Encoding.base64UrlEncodeToString;
import static io.nats.client.support.Encoding.uriDecode;
import static io.nats.client.support.Encoding.*;
import static io.nats.client.support.NatsConstants.*;
import static io.nats.client.support.SSLUtils.DEFAULT_TLS_ALGORITHM;
import static io.nats.client.support.Validator.*;
Expand Down Expand Up @@ -2435,9 +2434,9 @@ public CharBuffer buildProtocolConnectOptionsString(String serverURI, boolean in

String encodedSig = base64UrlEncodeToString(sig);

appendOption(connectString, Options.OPTION_NKEY, nkey, true, true);
appendOption(connectString, Options.OPTION_NKEY, nkey, true);
appendOption(connectString, Options.OPTION_SIG, encodedSig, true, true);
appendOption(connectString, Options.OPTION_JWT, jwt, true, true);
appendOption(connectString, Options.OPTION_JWT, jwt, true);
}

String uriUser = null;
Expand Down Expand Up @@ -2465,24 +2464,24 @@ public CharBuffer buildProtocolConnectOptionsString(String serverURI, boolean in
}

if (uriUser != null) {
appendOption(connectString, Options.OPTION_USER, uriUser, true, true);
appendOption(connectString, Options.OPTION_USER, jsonEncode(uriUser), true, true);
}
else if (this.username != null) {
appendOption(connectString, Options.OPTION_USER, this.username, true, true);
appendOption(connectString, Options.OPTION_USER, jsonEncode(this.username), true, true);
}

if (uriPass != null) {
appendOption(connectString, Options.OPTION_PASSWORD, uriPass, true, true);
appendOption(connectString, Options.OPTION_PASSWORD, jsonEncode(uriPass), true, true);
}
else if (this.password != null) {
appendOption(connectString, Options.OPTION_PASSWORD, this.password, true, true);
appendOption(connectString, Options.OPTION_PASSWORD, jsonEncode(this.password), true, true);
}

if (uriToken != null) {
appendOption(connectString, Options.OPTION_AUTH_TOKEN, uriToken, true, true);
}
else if (this.token != null) {
appendOption(connectString, Options.OPTION_AUTH_TOKEN, this.token, true, true);
appendOption(connectString, Options.OPTION_AUTH_TOKEN, this.token, true);
}
}

Expand All @@ -2500,10 +2499,11 @@ private static void appendOption(CharBuffer builder, String key, String value, b
_appendOptionEnd(builder, quotes);
}

private static void appendOption(CharBuffer builder, String key, char[] value, boolean quotes, boolean comma) {
_appendStart(builder, key, quotes, comma);
@SuppressWarnings("SameParameterValue")
private static void appendOption(CharBuffer builder, String key, char[] value, boolean comma) {
_appendStart(builder, key, true, comma);
builder.put(value);
_appendOptionEnd(builder, quotes);
_appendOptionEnd(builder, true);
}

private static void _appendStart(CharBuffer builder, String key, boolean quotes, boolean comma) {
Expand Down
84 changes: 49 additions & 35 deletions src/main/java/io/nats/client/support/Encoding.java
Original file line number Diff line number Diff line change
Expand Up @@ -270,45 +270,59 @@ public static String jsonEncode(String s) {
public static StringBuilder jsonEncode(StringBuilder sb, String s) {
int len = s.length();
for (int x = 0; x < len; x++) {
char ch = s.charAt(x);
switch (ch) {
case '"':
sb.append("\\\"");
break;
case '\\':
sb.append("\\\\");
break;
case '\b':
sb.append("\\b");
break;
case '\f':
sb.append("\\f");
break;
case '\n':
sb.append("\\n");
break;
case '\r':
sb.append("\\r");
break;
case '\t':
sb.append("\\t");
break;
case '/':
sb.append("\\/");
break;
default:
if (ch < ' ') {
sb.append(String.format("\\u%04x", (int) ch));
}
else {
sb.append(ch);
}
break;
}
appendChar(sb, s.charAt(x));
}
return sb;
}

public static String jsonEncode(char[] chars) {
return jsonEncode(new StringBuilder(), chars).toString();
}

public static StringBuilder jsonEncode(StringBuilder sb, char[] chars) {
for (char aChar : chars) {
appendChar(sb, aChar);
}
return sb;
}

private static void appendChar(StringBuilder sb, char ch) {
switch (ch) {
case '"':
sb.append("\\\"");
break;
case '\\':
sb.append("\\\\");
break;
case '\b':
sb.append("\\b");
break;
case '\f':
sb.append("\\f");
break;
case '\n':
sb.append("\\n");
break;
case '\r':
sb.append("\\r");
break;
case '\t':
sb.append("\\t");
break;
case '/':
sb.append("\\/");
break;
default:
if (ch < ' ') {
sb.append(String.format("\\u%04x", (int) ch));
}
else {
sb.append(ch);
}
break;
}
}

public static String uriDecode(String source) {
try {
return URLDecoder.decode(source.replace("+", "%2B"), "UTF-8");
Expand Down
28 changes: 28 additions & 0 deletions src/test/java/io/nats/client/AuthTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import io.nats.client.utils.TestBase;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledOnOs;

import javax.net.ssl.SSLContext;
import java.io.BufferedWriter;
Expand All @@ -34,6 +35,7 @@
import java.util.concurrent.TimeUnit;

import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.condition.OS.WINDOWS;

public class AuthTests extends TestBase {

Expand Down Expand Up @@ -88,6 +90,32 @@ private void assertEncoded(String encoded, int port) throws IOException, Interru
c.close();
}

@Test
@EnabledOnOs({ WINDOWS })
public void testNeedsJsonEncoding() throws Exception {
assertNeedsJsonEncoding("\n");
assertNeedsJsonEncoding("\b");
assertNeedsJsonEncoding("\f");
assertNeedsJsonEncoding("\r");
assertNeedsJsonEncoding("\t");
assertNeedsJsonEncoding("/");
assertNeedsJsonEncoding("" + (char)9);
assertNeedsJsonEncoding("\\");
}

private static void assertNeedsJsonEncoding(String test) throws Exception {
String user = "u" + test + "u";
String pass = "p" + test + "p";
String[] customArgs = {"--user", "\"" + user + "\"", "--pass", "\"" + pass + "\""};
try (NatsTestServer ts = new NatsTestServer(customArgs, false)) {
// See config file for user/pass
Options options = new Options.Builder().server("nats://localhost:" + ts.getPort())
.userInfo(user, pass)
.maxReconnects(0).build();
assertCanConnect(options);
}
}

@Test
public void testUserPassOnReconnect() throws Exception {
ListenerForTesting listener = new ListenerForTesting();
Expand Down

0 comments on commit fd76e1d

Please sign in to comment.