Skip to content

Equals symbols in base64 encoded data are escaped to HTML Safe characters resulting in errors when making HTTP calls. #233

@archcosmo

Description

@archcosmo

I've noticed this when creating a secret with .dockerconfigjson set to an array of bytes that is base64 encoded to a string that contains an equals character. The result is '\u003d' is inserted in to the request body which then results in an error as Kubernetes cannot parse the invalid base64 characters.

It seems to occur in the JSON class which uses Gson to encode the data, but the Gson htmlSafe if true by default, so the characters are escaped.

This demonstrates the issue:

package comp3200.am3g15.forestgrowthsrc.k8s.client; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import io.kubernetes.client.JSON; import io.kubernetes.client.models.V1Secret; import okio.ByteString; import java.io.IOException; import java.util.HashMap; import java.util.Map; public class Base64Test { public static void main(String[] args) { V1Secret secret = new V1Secret(); Map<String, byte[]> secretData = new HashMap<>(); secretData.put(".dockerconfigjson", new String("{\"auths\":{\"server\":{\"username\":\"username\",\"password\":\"password\",\"email\":\"email\",\"auth\":\"authhh\"}}}").getBytes()); secret.setData(secretData); //What occurs when CoreV1Api.createNamespacedSecret() is called JSON json = new JSON(); String erroneous = json.serialize(secret); //The Equivalent without the JSON class Gson gson = new GsonBuilder().registerTypeAdapter(byte[].class, new ByteArrayAdapter()).create(); String stillErroneous = gson.toJson(secret); //With HTML Safety Turned Off gson = new GsonBuilder().disableHtmlEscaping().registerTypeAdapter(byte[].class, new ByteArrayAdapter()).create(); String correct = gson.toJson(secret); System.out.printf("Bad: %s\nBad: %s\nCorrect: %s", erroneous, stillErroneous, correct); } //Pulled from the JSON class public static class ByteArrayAdapter extends TypeAdapter<byte[]> { public ByteArrayAdapter() { } public void write(JsonWriter out, byte[] value) throws IOException { if (value == null) { out.nullValue(); } else { out.value(ByteString.of(value).base64()); } } public byte[] read(JsonReader in) throws IOException { switch(in.peek()) { case NULL: in.nextNull(); return null; default: String bytesAsBase64 = in.nextString(); ByteString byteString = ByteString.decodeBase64(bytesAsBase64); return byteString.toByteArray(); } } } } 

The output of which is:

Bad: {"data":{".dockerconfigjson":"eyJhdXRocyI6eyJzZXJ2ZXIiOnsidXNlcm5hbWUiOiJ1c2VybmFtZSIsInBhc3N3b3JkIjoicGFzc3dvcmQiLCJlbWFpbCI6ImVtYWlsIiwiYXV0aCI6ImF1dGhoaCJ9fX0\u003d"}} Bad: {"data":{".dockerconfigjson":"eyJhdXRocyI6eyJzZXJ2ZXIiOnsidXNlcm5hbWUiOiJ1c2VybmFtZSIsInBhc3N3b3JkIjoicGFzc3dvcmQiLCJlbWFpbCI6ImVtYWlsIiwiYXV0aCI6ImF1dGhoaCJ9fX0\u003d"}} Correct: {"data":{".dockerconfigjson":"eyJhdXRocyI6eyJzZXJ2ZXIiOnsidXNlcm5hbWUiOiJ1c2VybmFtZSIsInBhc3N3b3JkIjoicGFzc3dvcmQiLCJlbWFpbCI6ImVtYWlsIiwiYXV0aCI6ImF1dGhoaCJ9fX0="}} 

Notice the presence of \u003d at the end of the first two strings.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions