So I am trying to decode a JWT token in my android app when using the method Base64.decodeBase64() from import org.apache.commons.codec.binary.Base64;
When I print the string I get from the decoded token, I get these characters at the end of the string "������", when it really should be "}}"
The code is given below:
String token = loadFromCache("token");
String[] split_String = token.split("\\.");
String base64EncodedBody = split_String[1];
System.out.println("BASE64 Body: " + base64EncodedBody);
String body = new String(Base64.decodeBase64(base64EncodedBody.getBytes()));
System.out.println("BODY: " + body);
try {
JSONObject jsonObject = new JSONObject(body).getJSONObject("employee");
} catch (JSONException e) {
e.printStackTrace();
}
the token is valid, and I do indeed get almost all the values correct. It's just that it ends with the characters ������ instead of }}. Any help appreciated
Use Android's Base64 class:
String body = new String(Base64.decode(base64EncodedBody.getBytes(Charset.forName("UTF-8")), Base64.NO_WRAP), Charset.forName("UTF-8"));
With your own Base64 flag and encoding.
An alternative solution that uses "import com.auth0.android.jwt.JWT;"
return new JWT(loadFromCache("token")).getClaim("employee").asObject(Employee.class);
This returns the claim "employee" as a Employee object so i can just use getters to get the values. Example: employee.getId() etc..
NOTE: the loadFromCache method just returns the value specified by its key. Here I want the value defined by the key "token".
Related
Say I have a URL
http://example.com/query?q=
and I have a query entered by the user such as:
random word £500 bank $
I want the result to be a properly encoded URL:
http://example.com/query?q=random%20word%20%A3500%20bank%20%24
What's the best way to achieve this? I tried URLEncoder and creating URI/URL objects but none of them come out quite right.
URLEncoder is the way to go. You only need to keep in mind to encode only the individual query string parameter name and/or value, not the entire URL, for sure not the query string parameter separator character & nor the parameter name-value separator character =.
String q = "random word £500 bank $";
String url = "https://example.com?q=" + URLEncoder.encode(q, StandardCharsets.UTF_8);
When you're still not on Java 10 or newer, then use StandardCharsets.UTF_8.toString() as charset argument, or when you're still not on Java 7 or newer, then use "UTF-8".
Note that spaces in query parameters are represented by +, not %20, which is legitimately valid. The %20 is usually to be used to represent spaces in URI itself (the part before the URI-query string separator character ?), not in query string (the part after ?).
Also note that there are three encode() methods. One without Charset as second argument and another with String as second argument which throws a checked exception. The one without Charset argument is deprecated. Never use it and always specify the Charset argument. The javadoc even explicitly recommends to use the UTF-8 encoding, as mandated by RFC3986 and W3C.
All other characters are unsafe and are first converted into one or more bytes using some encoding scheme. Then each byte is represented by the 3-character string "%xy", where xy is the two-digit hexadecimal representation of the byte. The recommended encoding scheme to use is UTF-8. However, for compatibility reasons, if an encoding is not specified, then the default encoding of the platform is used.
See also:
What every web developer must know about URL encoding
I would not use URLEncoder. Besides being incorrectly named (URLEncoder has nothing to do with URLs), inefficient (it uses a StringBuffer instead of Builder and does a couple of other things that are slow) Its also way too easy to screw it up.
Instead I would use URIBuilder or Spring's org.springframework.web.util.UriUtils.encodeQuery or Commons Apache HttpClient.
The reason being you have to escape the query parameters name (ie BalusC's answer q) differently than the parameter value.
The only downside to the above (that I found out painfully) is that URL's are not a true subset of URI's.
Sample code:
import org.apache.http.client.utils.URIBuilder;
URIBuilder ub = new URIBuilder("http://example.com/query");
ub.addParameter("q", "random word £500 bank \$");
String url = ub.toString();
// Result: http://example.com/query?q=random+word+%C2%A3500+bank+%24
You need to first create a URI like:
String urlStr = "http://www.example.com/CEREC® Materials & Accessories/IPS Empress® CAD.pdf"
URL url = new URL(urlStr);
URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
Then convert that URI to an ASCII string:
urlStr = uri.toASCIIString();
Now your URL string is completely encoded. First we did simple URL encoding and then we converted it to an ASCII string to make sure no character outside US-ASCII remained in the string. This is exactly how browsers do it.
Guava 15 has now added a set of straightforward URL escapers.
The code
URL url = new URL("http://example.com/query?q=random word £500 bank $");
URI uri = new URI(url.getProtocol(), url.getUserInfo(), IDN.toASCII(url.getHost()), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
String correctEncodedURL = uri.toASCIIString();
System.out.println(correctEncodedURL);
Prints
http://example.com/query?q=random%20word%20%C2%A3500%20bank%20$
What is happening here?
1. Split URL into structural parts. Use java.net.URL for it.
2. Encode each structural part properly!
3. Use IDN.toASCII(putDomainNameHere) to Punycode encode the hostname!
4. Use java.net.URI.toASCIIString() to percent-encode, NFC encoded Unicode - (better would be NFKC!). For more information, see: How to encode properly this URL
In some cases it is advisable to check if the URL is already encoded. Also replace '+' encoded spaces with '%20' encoded spaces.
Here are some examples that will also work properly
{
"in" : "http://نامهای.com/",
"out" : "http://xn--mgba3gch31f.com/"
},{
"in" : "http://www.example.com/‥/foo",
"out" : "http://www.example.com/%E2%80%A5/foo"
},{
"in" : "http://search.barnesandnoble.com/booksearch/first book.pdf",
"out" : "http://search.barnesandnoble.com/booksearch/first%20book.pdf"
}, {
"in" : "http://example.com/query?q=random word £500 bank $",
"out" : "http://example.com/query?q=random%20word%20%C2%A3500%20bank%20$"
}
The solution passes around 100 of the test cases provided by Web Platform Tests.
Using Spring's UriComponentsBuilder:
UriComponentsBuilder
.fromUriString(url)
.build()
.encode()
.toUri()
The Apache HttpComponents library provides a neat option for building and encoding query parameters.
With HttpComponents 4.x use:
URLEncodedUtils
For HttpClient 3.x use:
EncodingUtil
Here's a method you can use in your code to convert a URL string and map of parameters to a valid encoded URL string containing the query parameters.
String addQueryStringToUrlString(String url, final Map<Object, Object> parameters) throws UnsupportedEncodingException {
if (parameters == null) {
return url;
}
for (Map.Entry<Object, Object> parameter : parameters.entrySet()) {
final String encodedKey = URLEncoder.encode(parameter.getKey().toString(), "UTF-8");
final String encodedValue = URLEncoder.encode(parameter.getValue().toString(), "UTF-8");
if (!url.contains("?")) {
url += "?" + encodedKey + "=" + encodedValue;
} else {
url += "&" + encodedKey + "=" + encodedValue;
}
}
return url;
}
In Android, I would use this code:
Uri myUI = Uri.parse("http://example.com/query").buildUpon().appendQueryParameter("q", "random word A3500 bank 24").build();
Where Uri is a android.net.Uri
In my case I just needed to pass the whole URL and encode only the value of each parameters.
I didn't find common code to do that, so (!!) so I created this small method to do the job:
public static String encodeUrl(String url) throws Exception {
if (url == null || !url.contains("?")) {
return url;
}
List<String> list = new ArrayList<>();
String rootUrl = url.split("\\?")[0] + "?";
String paramsUrl = url.replace(rootUrl, "");
List<String> paramsUrlList = Arrays.asList(paramsUrl.split("&"));
for (String param : paramsUrlList) {
if (param.contains("=")) {
String key = param.split("=")[0];
String value = param.replace(key + "=", "");
list.add(key + "=" + URLEncoder.encode(value, "UTF-8"));
}
else {
list.add(param);
}
}
return rootUrl + StringUtils.join(list, "&");
}
public static String decodeUrl(String url) throws Exception {
return URLDecoder.decode(url, "UTF-8");
}
It uses Apache Commons' org.apache.commons.lang3.StringUtils.
Use this:
URLEncoder.encode(query, StandardCharsets.UTF_8.displayName());
or this:
URLEncoder.encode(query, "UTF-8");
You can use the following code.
String encodedUrl1 = UriUtils.encodeQuery(query, "UTF-8"); // No change
String encodedUrl2 = URLEncoder.encode(query, "UTF-8"); // Changed
String encodedUrl3 = URLEncoder.encode(query, StandardCharsets.UTF_8.displayName()); // Changed
System.out.println("url1 " + encodedUrl1 + "\n" + "url2=" + encodedUrl2 + "\n" + "url3=" + encodedUrl3);
From Angular, there is one parameter and the value of that parameter is Ébénisterie but when I print the value of that variable in java then I got Ã?bénisterie can you please let me know how I can convert it to original text Ébénisterie? Which Encode/decode I have to apply?
I have tried the following thing.
new String(readable.getBytes("ISO-8859-15"), "UTF-8");
new String(readable.getBytes("UTF-8"), "ISO-8859-15");
but it's not working.
String readable ="�bénisterie Distinction";
String test = null;
try {
test = new String(readable.getBytes("ISO-8859-15"), "UTF-8");
System.out.println("test"+test);
} catch (UnsupportedEncodingException e) {
}
Expected: Ébénisterie
Actual: �bénisterie
After long research didn't find anything.
So got one solution in mind that BASE64 Encode decode so now from Angularjs sending encoded text and In java side, I have decoded the text.
Here, is the sample code
Angularjs
window.btoa("Ébénisterie")
JAVA
String actualString= new String(Base64.getDecoder().decode("ENCODED STRING"));
I want to get full message body. So I try:
Message gmailMessage = service.users().messages().get("me", messageId).setFormat("full").execute();
That to get body, I try:
gmailMessage.getPayload().getBody().getData()
but result always null. How to get full message body?
To get the data from your gmailMessage, you can use gmailMessage.payload.parts[0].body.data. If you want to decode it into readable text, you can do the following:
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;
System.out.println(StringUtils.newStringUtf8(Base64.decodeBase64(gmailMessage.payload.parts[0].body.data)));
I tried this way, since message.getPayload().getBody().getParts() was always null
import com.google.api.client.repackaged.org.apache.commons.codec.binary.Base64;
import com.google.api.client.repackaged.org.apache.commons.codec.binary.StringUtils;
(...)
Message message = service.users().messages().get(user, m.getId()).execute();
MessagePart part = message.getPayload();
System.out.println(StringUtils.newStringUtf8(Base64.decodeBase64(part.getBody().getData())));
And the result is pure HTML String
I found more interesting way how to resolve a full body message (and not only body):
System.out.println(StringUtils.newStringUtf8( Base64.decodeBase64 (message.getRaw())));
here is the solution in c# code gmail API v1 to read the email body content:
var request = _gmailService.Users.Messages.Get("me", mail.Id);
request.Format = UsersResource.MessagesResource.GetRequest.FormatEnum.Full;
and to solve the data error
var res = message.Payload.Body.Data.Replace("-", "+").Replace("_", "/");
byte[] bodyBytes = Convert.FromBase64String(res);
string val = Encoding.UTF8.GetString(bodyBytes);
If you have the message (com.google.api.services.gmail.model.Message) you could use the following methods:
public String getContent(Message message) {
StringBuilder stringBuilder = new StringBuilder();
try {
getPlainTextFromMessageParts(message.getPayload().getParts(), stringBuilder);
byte[] bodyBytes = Base64.decodeBase64(stringBuilder.toString());
String text = new String(bodyBytes, StandardCharsets.UTF_8);
return text;
} catch (UnsupportedEncodingException e) {
logger.error("UnsupportedEncoding: " + e.toString());
return message.getSnippet();
}
}
private void getPlainTextFromMessageParts(List<MessagePart> messageParts, StringBuilder stringBuilder) {
for (MessagePart messagePart : messageParts) {
if (messagePart.getMimeType().equals("text/plain")) {
stringBuilder.append(messagePart.getBody().getData());
}
if (messagePart.getParts() != null) {
getPlainTextFromMessageParts(messagePart.getParts(), stringBuilder);
}
}
}
It combines all message parts with the mimeType "text/plain" and returns it as one string.
When we get full message. The message body is inside Parts.
This is an example in which message headers (Date, From, To and Subject) are displayed and Message Body as a plain text is displayed. Parts in Payload returns both type of messages (plain text and formatted text). I was interested in Plain text.
Message msg = service.users().messages().get(user, message.getId()).setFormat("full").execute();
// Displaying Message Header Information
for (MessagePartHeader header : msg.getPayload().getHeaders()) {
if (header.getName().contains("Date") || header.getName().contains("From") || header.getName().contains("To")
|| header.getName().contains("Subject"))
System.out.println(header.getName() + ":" + header.getValue());
}
// Displaying Message Body as a Plain Text
for (MessagePart msgPart : msg.getPayload().getParts()) {
if (msgPart.getMimeType().contains("text/plain"))
System.out.println(new String(Base64.decodeBase64(msgPart.getBody().getData())));
}
Base on the #Tholle comment I've made something like that
Message message = service.users().messages()
.get(user, messageHolder.getId()).execute();
System.out.println(StringUtils.newStringUtf8(Base64.decodeBase64(
message.getPayload().getParts().get(0).getBody().getData())));
There is a method to decode the body:
final String body = new String(message.getPayload().getParts().get(0).getBody().decodeData());
Message message = service.users().messages().get(user, messageId).execute();
//Print email body
List<MessagePart> parts = message.getPayload().getParts();
String data = parts.get(0).getBody().getData();
String body = new String(BaseEncoding.base64Url().decode(data));
I'm building a simulator to post JSON data to a service I'm running.
The JSON should look like this:
{"sensor":
{"id":"SENSOR1","name":"SENSOR","type":"Temperature","value":100.12,"lastDateValue":"\/Date(1382459367723)\/"}
}
I tried this with the "Advanced REST Client" in Chrome and this works fine. The date get's parsed properly by the ServiceStack webservice.
So, the point is to write a sensor simulator that posts data like this to the web service.
I created this in Java, so I could run it on my raspberry pi.
This is the code:
public static void main(String[] args) {
String url = "http://localhost:63003/api/sensors";
String sensorname = "Simulated sensor";
int currentTemp = 10;
String dateString = "\\" + "/Date(" + System.currentTimeMillis() + ")\\" + "/";
System.out.println(dateString);
System.out.println("I'm going to post some data to: " + url);
//Creating the JSON Object
JSONObject data = new JSONObject();
data.put("id", sensorname);
data.put("name", sensorname);
data.put("type", "Temperature");
data.put("value", currentTemp);
data.put("lastDateValue", dateString);
JSONObject sensor = new JSONObject().put("sensor", data);
//Print out the data to be sent
StringWriter out = new StringWriter();
sensor.write(out);
String jsonText = out.toString();
System.out.print(jsonText);
//Sending the object
HttpClient c = new DefaultHttpClient();
HttpPost p = new HttpPost(url);
p.setEntity(new StringEntity(sensor.toString(), ContentType.create("application/json")));
try {
HttpResponse r = c.execute(p);
} catch (Exception e) {
e.printStackTrace();
}
}
The output of this program is as follows:
\/Date(1382459367723)\/
I'm going to post some data to: http://localhost:63003/api/sensors
{"sensor":{"lastDateValue":"\\/Date(1382459367723)\\/","id":"Simulated sensor","name":"Simulated sensor","value":10,"type":"Temperature"}}
The issue here is that the JSONObject string still contains these escape characters. But when I print the string in the beginning it does not contain the escape characters. Is there any way to get rid of these? My service can't parse these..
This is a sample of what I send with the rest client in chrome:
{"sensor":{"id":"I too, am a sensor!","name":"Willy","type":"Temperature","value":100.12,"lastDateValue":"\/Date(1382459367723)\/"}}
JSONObject is correctly encoding the string. This page describes how string literals are to be escaped in JavaScript (and, by extension, JSON). The following note is important to understanding what happens in your example:
For characters not listed in Table 2.1, a preceding backslash is ignored, but this usage is deprecated and should be avoided.
Your example ("\/Date(1382459367723)\/") uses a preceding backslash before a /. Because / is not in table 2.1, the \ should simply be ignored. If your service doesn't ignore the \, then it either has a bug, or is not a JSON parser (perhaps it uses a data format which is similar to, but not quite, JSON).
Since you need to generate non-conforming JSON, you won't be able to use standard tools to do so. Your two options are to write your own not-quite-JSON encoder, or to avoid characters which must be escaped, such as \ and ".
#pburka is correct. If you want to send it in \/Date(1382459367723)\/ format, try escaping the blackslash twice as below
String dateString = "\\\\" + "/Date(" + System.currentTimeMillis() + ")\\\\" + "/";
In the first pass, dateString will make it as \\/Date(1382459367723)\\/ and finally JSONObject will add extra backslashes internally to it's buffer i.e \\\/Date(1382459367723)\\\/ so that the blackslashes before / will be ignored according to JSON parsing rules and you would get the desired result i.e \/Date(1382459367723)\/
I am writing a Java lib and need to perform a request to a URL - currently using async-http-client from ning - and fetch its content. So I have a get method that returns a String
of the content of the fetched document. However, to be able to get it, I must perform a HTTP basic authentication and I'm not succeeding at this in my Java code:
public String get(String token) throws IOException {
String fetchURL = "https://www.eventick.com.br/api/v1/events/492";
try {
String encoded = URLEncoder.encode(token + ":", "UTF-8");
return this.asyncClient.prepareGet(fetchURL)
.addHeader("Authorization", "Basic " + encoded).execute().get().getResponseBody();
}
}
The code returns no error, it just doesn't fetch the URL because the authentication header is not being properly set, somehow.
With curl -u option I can easily get what I want:
curl https://www.eventick.com.br/api/v1/events/492 -u 'xxxxxxxxxxxxxxx:'
Returns:
{"events":[{"id":492,"title":"Festa da Bagaceira","venue":"Mangueirão de Paulista",
"slug":"bagaceira-fest", "start_at":"2012-07-29T16:00:00-03:00",
"links":{"tickets":[{"id":738,"name":"Normal"}]}}]}
How can this be done in Java? With the async-http-client lib? Or if you know how to do it using another way..
Any help is welcome!
You're close. You need to base 64 encode rather than URL encode. That is, you need
String encoded = Base64.getEncoder().encodeToString((user + ':' + password).getBytes(StandardCharsets.UTF_8));
rather than
String encoded = URLEncoder.encode(token + ":", "UTF-8");
(Note that for the benefit of others, since I'm answering 2 years later, in my answer I'm using the more standard "user:password" whereas your question has "token:". If "token:" is what you needed, then stick with that. But maybe that was part of the problem, too?)
Here is a short, self-contained, correct example
package so17380731;
import com.ning.http.client.AsyncHttpClient;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import javax.ws.rs.core.HttpHeaders;
public class BasicAuth {
public static void main(String... args) throws Exception {
try(AsyncHttpClient asyncClient = new AsyncHttpClient()) {
final String user = "StackOverflow";
final String password = "17380731";
final String fetchURL = "https://www.eventick.com.br/api/v1/events/492";
final String encoded = Base64.getEncoder().encodeToString((user + ':' + password).getBytes(StandardCharsets.UTF_8));
final String body = asyncClient
.prepareGet(fetchURL)
.addHeader(HttpHeaders.AUTHORIZATION, "Basic " + encoded)
.execute()
.get()
.getResponseBody(StandardCharsets.UTF_8.name());
System.out.println(body);
}
}
}
The documentation is very sketchy, but I think that you need to use a RequestBuilder following the pattern shown in the Request javadoc:
Request r = new RequestBuilder().setUrl("url")
.setRealm((new Realm.RealmBuilder()).setPrincipal(user)
.setPassword(admin)
.setRealmName("MyRealm")
.setScheme(Realm.AuthScheme.DIGEST).build());
r.execute();
(Obviously, this example is not Basic Auth, but there are clues as to how you would do it.)
FWIW, one problem with your current code is that a Basic Auth header uses base64 encoding not URL encoding; see the RFC2617 for details.
basically, do it like this:
BoundRequestBuilder request = asyncHttpClient
.preparePost(getUrl())
.setHeader("Accept", "application/json")
.setHeader("Content-Type", "application/json")
.setRealm(org.asynchttpclient.Dsl.basicAuthRealm(getUser(), getPassword()))
// ^^^^^^^^^^^-- this is the important part
.setBody(json);
Test can be found here:
https://github.com/AsyncHttpClient/async-http-client/blob/master/client/src/test/java/org/asynchttpclient/BasicAuthTest.java
This is also another way of adding Basic Authorization,
you can use any of two the classes for your use AsyncHttpClient,HttpClient,in this case i will use AsyncHttpClient
AsyncHttpClient client=new AsyncHttpClient();
Request request = client.prepareGet("https://www.eventick.com.br/api/v1/events/492").
setHeader("Content-Type","application/json")
.setHeader("Authorization","Basic b2pAbml1LXR2LmNvbTpnMGFRNzVDUnhzQ0ZleFQ=")
.setBody(jsonObjectRepresentation.toString()).build();
after adding header part
ListenableFuture<Response> r = null;
//ListenableFuture<Integer> f= null;
try{
r = client.executeRequest(request);
System.out.println(r.get().getResponseBody());
}catch(IOException e){
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
client.close();
it may be useful for you