kintone-labs / java-sdk

Apache License 2.0
9 stars 13 forks source link

Illegal character(s) in message header value when password is too long #10

Closed hungtp closed 7 years ago

hungtp commented 7 years ago

It seems that you used Base64 when connect with Basic Authentication which cause to create break line when encoded "username:password" string is too long (>76 character). Can you update to fix that?

dtduc91 commented 7 years ago

Dear hungtp, Can you describe all the steps which caused this issue?

I have tried to set basic auth with length > 76 characters, it's still working fine ;)

note: If your auth is invalid, the sdk will throw error look like this com.cybozu.kintone.database.exception.DBException: http status error(401)

Re-Produce:

ON Cybozu Store, set Basic Auth with username is kintonekintonekintonekintone and the password is kintonekintonekintonekintonekintonekintonekintonekintonekintone => The header request is: Authorization: Basic a2ludG9uZWtpbnRvbmVraW50b25la2ludG9uZTpraW50b25la2ludG9uZWtpbnRvbmVraW50b25la2ludG9uZWtpbnRvbmVraW50b25la2ludG9uZWtpbnRvbmU=

Source Code:

// create connection
Connection db;
try {
    db = new Connection("domain.kintone.com", "username", "password");
    db.setBasicAuth("kintone",
            "kintonekintonekintonekintonekintonekintonekintonekintonekintone");
} catch (Exception e) {
    return;
}

 String query = "";

// // select records
 ResultSet rs = null;
try {
    // get records with total count
    rs = db.selectWithTotalCount(app, query);
} catch (DBException e1) {
    e1.printStackTrace();
}
long totalCount = rs.getTotalCount();

ArrayList<Record> list = new ArrayList<Record>();

System.out.println("Total: " + String.valueOf(totalCount));
while (rs.next()) {
    // record number
    long recNo = rs.getId();
    String text = rs.getString("Text_field_code");
    System.out.println(recNo);
    System.out.println(text);
}

Result:

Total: 2
2
www
1
iiii

Process finished with exit code 0

Please don't hesitate let me know if you have further question.

dtduc

hungtp commented 7 years ago

Sorry, my mistake. What I meant was the auth string generated for header value X-Cybozu-Authorization in line 109 in Connection.java:

this.auth = (new BASE64Encoder()).encode((login + ":" + password).getBytes());

So, in your example, if the username and password to login to Kintone is too long then it will result in error when connect with sdk. Source code:

db = new Connection("domain.kintone.com", "username", "password");

to something like

db = new Connection("domain.kintone.com", "username", "kintonekintonekintonekintonekintonekintonekintonekintonekintone");

Result:

Exception in thread "main" java.lang.IllegalArgumentException: Illegal character(s) in message header value: dXNlcm5hbWU6a2ludG9uZWtpbnRvbmVraW50b25la2ludG9uZWtpbnRvbmVraW50b25la2ludG9u
ZWtpbnRvbmVraW50b25l
    at sun.net.www.protocol.http.HttpURLConnection.checkMessageHeader(HttpURLConnection.java:508)
    at sun.net.www.protocol.http.HttpURLConnection.isExternalMessageHeaderAllowed(HttpURLConnection.java:459)
    at sun.net.www.protocol.http.HttpURLConnection.setRequestProperty(HttpURLConnection.java:3018)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.setRequestProperty(HttpsURLConnectionImpl.java:316)
    at com.cybozu.kintone.database.Connection.setHTTPHeaders(Connection.java:385)
    at com.cybozu.kintone.database.Connection.request(Connection.java:434)
    at com.cybozu.kintone.database.Connection.request(Connection.java:374)
    at com.cybozu.kintone.database.Connection.select(Connection.java:806)
    at com.cybozu.kintone.database.Connection.selectWithTotalCount(Connection.java:727)
    at com.cybozu.kintone.samples.SdkSample.main(SdkSample.java:57)

It seems the SDK is using the old "sun.misc.BASE64Encoder" which will breaking a new line "\n" if the encoded string is too long (>76 characters).

dtduc91 commented 7 years ago

Dear hungtp,

Thank you for helping me detected this issue, I have just found out the solution which can resolve your issue, it will like below:

In Connection.java:

  1. Replace line 58 with import java.util.Base64;
  2. Replace line 109 with this.auth = Base64.getEncoder().encodeToString((login + ":" + password).getBytes());

I hope you can resolve this issue ;)

hungtp commented 7 years ago

Dear dtduc91,

Thank you for the solution. Do you have plan to update the github source code?

dtduc91 commented 7 years ago

Of course yes, let's wait for new one ;)