Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot decode base64 with java.util.base64. Removing org.postgresql.util.Base64 has a side effect #2447

Closed
lchevallier69 opened this issue Feb 9, 2022 · 16 comments

Comments

@lchevallier69
Copy link

lchevallier69 commented Feb 9, 2022

Please read https://stackoverflow.com/help/minimal-reproducible-example

Description
As org.postgresql.util.Base64 has been removed from the driver, it is impossible to read postgresql encoded base64 data in java

Driver Version?
42.3.2
Java Version?
Java 8
OS Version?
Windows
PostgreSQL Version?
11

the embbeded version of decoder can read this byte array without problem, but the java.utils.base64 cannot :

Logs
java.lang.IllegalArgumentException: Illegal base64 character a
at java.util.Base64$Decoder.decode0(Base64.java:714)
at java.util.Base64$Decoder.decode(Base64.java:526)

Using the following template code make sure the bug can be replicated in the driver alone.

import java.util.Base64;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class Base64Test {

  public static void main(String[] args) throws SQLException {
    //		String encoded =
    // "AQIAACBqCAAAAwAAAMN20tCUhSlBarkqSp7jWEEH4Ur2BYcpQS9gelKu41hBtONRfiyJKUH2QH87xuNYQQ==";
    //		byte[] encodedBytes = encoded.getBytes();
    //		byte[] b = Base64.getDecoder().decode(encodedBytes);
    String url = "jdbc:postgresql://localhost:5432/bacasable";
    Properties props = new Properties();
    props.setProperty("user", "postgres");
    props.setProperty("password", "postgre$69");
    try (Connection conn = DriverManager.getConnection(url, props)) {
      try (Statement statement = conn.createStatement()) {
        try (ResultSet rs =
            statement.executeQuery(
                "select encode(ST_AsEWKB(geom), 'base64') as encoded from relations.reseau")) {
          if (rs.next()) {
            byte[] bytes = rs.getBytes(1);
            Base64.getDecoder().decode(bytes);
          }
        }
      }
    }
  }
}

@lchevallier69
Copy link
Author

seems to be related to 1994

@sehrope
Copy link
Member

sehrope commented Feb 9, 2022

What's the base64 text of the data?

@lchevallier69
Copy link
Author

here is the String from the query
AQIAACBqCAAAAwAAAMN20tCUhSlBarkqSp7jWEEH4Ur2BYcpQS9gelKu41hBtONRfiyJKUH2QH87
xuNYQQ==

@sehrope
Copy link
Member

sehrope commented Feb 9, 2022

Does that have a newline break in it?

@lchevallier69
Copy link
Author

@lchevallier69
Copy link
Author

you must execute create extension postgis before restoring the dump

@sehrope
Copy link
Member

sehrope commented Feb 9, 2022

And previously you were using the org.postgresql.util.Base64 class to decode that data in your application code?

Specifically, I'm asking if this is happening within the driver's internal code or in your own code that is using that class.

When that class was removed it was assumed that it was only to be used internally by the driver. It wasn't considered part of the public interface of the driver.

@lchevallier69
Copy link
Author

here the test code complete

import java.util.Base64;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class Base64Test {

  public static void main(String[] args) throws SQLException {
    //		String encoded =
    // "AQIAACBqCAAAAwAAAMN20tCUhSlBarkqSp7jWEEH4Ur2BYcpQS9gelKu41hBtONRfiyJKUH2QH87xuNYQQ==";
    //		byte[] encodedBytes = encoded.getBytes();
    //		byte[] b = Base64.getDecoder().decode(encodedBytes);
    String url = "jdbc:postgresql://localhost:5432/bacasable";
    Properties props = new Properties();
    props.setProperty("user", "postgres");
    props.setProperty("password", "postgre$69");
    try (Connection conn = DriverManager.getConnection(url, props)) {
      try (Statement statement = conn.createStatement()) {
        try (ResultSet rs =
            statement.executeQuery(
                "select encode(ST_AsEWKB(geom), 'base64') as encoded from relations.reseau")) {
          if (rs.next()) {
            byte[] bytes = rs.getBytes(1);
            Base64.getDecoder().decode(bytes);
          }
        }
      }
    }
  }
}

@lchevallier69
Copy link
Author

lchevallier69 commented Feb 9, 2022

it seems that the string in PGAdmin is decodable, but it is not i read the result as byte array, it works properly with the org.postgresql.util.Base64 implementation.
In fact the String contains en chr(10) inside it , witch is a return char ! the byte[77] = 10

@lchevallier69
Copy link
Author

lchevallier69 commented Feb 9, 2022 via email

@jorsol
Copy link
Member

jorsol commented Feb 9, 2022

I haven't looked at this, but Base64 has 3 types of encoding schemes.

Have you tried if using getMimeDecoder() or getUrlDecoder() works?

@lchevallier69
Copy link
Author

Well Done !
Thats works correctly, in fact we should use getMimeDecoder(), that use RFC2045 scheme
Many thanks, i'll close the issue

@vlsi
Copy link
Member

vlsi commented Feb 10, 2022

I think we should resurrect org.postgresql.util.Base64 in @Deprecated state as the class has been removed without proper deprecation.

@sehrope
Copy link
Member

sehrope commented Feb 10, 2022

Are we going to consider everything in org.postgresql.util.* part of the public API?

@vlsi
Copy link
Member

vlsi commented Feb 10, 2022

Are there reasons to remove public classes/interfaces without going through the deprecation cycle?

@sehrope
Copy link
Member

sehrope commented Feb 10, 2022

If they're not part of the public API then I see no reason to maintain them as deprecated. The class being "public" is a Java limitation to allow it to be used across package boundaries within the library. Nothing in that org.postgresql.util.* package is part of the published API of the driver so it's not unreasonable for us to remove or modify without preserving backwards compatibility.

If the class was still in the tree and we hadn't published a version without it, then I'd probably be neutral on deprecating it first if it doesn't cause any maintenance headache (e.g. in this case it's entirely self contained class). But in this specific case we already removed it so the bar is higher to add it back.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants