Grails encoded params Post Request - java

I am trying to complete the Instagram Oauth flow,
I currently have the authorization code which I'm to exchange for the access token. I am to make an x-www-form-urlencoded POST request to this endpoint
"https://api.instagram.com/oauth/access_token?"
This is what I've done so far.
String query = "https://api.instagram.com/oauth/access_token/?client_id=" + clientId +"&client_secret="+ clientSecret+ "&grant_type=authorization_code&redirect_uri="+ redirectUri + "&code=" + code
String response = new URL(query).getText()
A JSON string is expected as response.
Please Keep in mind that I'm a beginner.

I haven't read the Instagram documentation but based on your example code there's a couple of things to keep in mind:
you mentioned that you have to make a POST request, your example makes a GET request
never build a URL with untrusted parameter values. This basically means: always encode parameters, never trust them.
There are dozens of 3rd party HTTP Request libraries that give you flexibility and easier insight into aspects like timeouts and redirects. Java 11 has a built-in HTTP client that might ease this as well. But building on your code provided in your question using basic Java connection primitives this might work:
URL url = new URL("https://api.instagram.com/oauth/access_token/?client_id=${URLEncoder.encode(clientId, 'UTF-8')}&client_secret=${URLEncoder.encode(clientSecret, 'UTF-8')}&grant_type=authorization_code&redirect_uri=${URLEncoder.encode(redirectUri, 'UTF-8')}&code=${URLEncoder.encode(code, 'UTF-8')}")
def jsonString = ((HttpURLConnection) url.openConnection()).with {
setRequestMethod('POST')
setRequestProperty('Accept', 'application/json')
setDoInput(true)
connect()
if (getResponseCode() >= 400)
throw new Exception("Error code = ${getResponseCode()}")
inputStream.text
}
Every URL parameter is encoded so that any non-URL safe characters they contain are made safe, then we tell the connection that it will be a 'POST' and that we expect to get back json as input. inputStream.text is groovy code that takes an inputstream from the connection and reads all of the contents and then closes the stream. Since it is the last line of the with closure it is automatically returned as the value of the closure and assigned to the variable jsonString.

Related

setEntity equivalent in OkHttp - Android

I'm migrating from the Apache HTTP legacy client to OkHttp and I'm having some problems finding equivalences between both. A couple of days ago I asked about credentials in this same subject and now I'm stuck again:
In the old implementation I have this:
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
reqGen.setCertReq(true);
MessageDigest digest = MessageDigest.getInstance("SHA256");
digest.update(myData);
TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA256, digest.digest(), BigInteger.valueOf(100));
byte[] enc_req = request.getEncoded();
myHttpPost.setEntity(new ByteArrayEntity(enc_req));
The most relevant line is the last one (as the others just build the request and, lucky enough, I won't need to change them), which adds the entity to the HttpPost.
Checking this answer it seems the entity of a request is
the majority of an HTTP request or response, consisting of some of the headers and the body, if present. It seems to be the entire request or response without the request or status line
But this definition confuses me as I can't find the equivalence to something with "headers and the body" in OkHttp. What I've tried:
MediaType textPlain = MediaType.parse("text/plain; charset=utf-8");
RequestBody requestBody = RequestBody.create(textPlain, request.getEncoded().toString());
Request myNewRequest = (new Request.Builder()).url(urlString).post(requestBody).build();
But it didn't work (I'm getting a 500 from the server). Does anyone know the correct equivalence?
I finally found the answer: I can use the TimeStampRequest encoded as I did before, without any modification. The change is, as I thought, only for the setEntity.
This is the request using OkHttp:
MediaType textPlain = MediaType.parse("binary");
RequestBody requestBody = RequestBody.create(textPlain, request.getEncoded());
Request myNewRequest = (new Request.Builder()).url(urlString).post(requestBody).build;
As you can see the only change from the previous code I tried is that I use binary as the MediaType, which make sense as we are sending a byte array (previously used ByteArrayEntity from the Apache client).
Hope it helps somebody.

How can I make a put request with okhttp3 without multipart body

My web service, which is a java servlet, accepts a put request with url params to take a specific action. The code below gets what I want done, but I would love to know if there is a better way to make a put request without adding a multipart body.
Do all put requests in Java Servlets expect a multipart body?
Do all put requests made using okhttp3 expect a multipart body?
Am I misunderstanding something else?
body = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("", "") // I would love to eliminate this.
.build();
request = new Request.Builder()
.url(url + "?my_param=" + URLEncoder.encode(myParam, "utf-8"))
.put(body)
.build();
response = client.newCall(request).execute();
From a pragmatic point of view, I'd say that you're looking at an implementation restriction of Servlets and/or OkHttp and it can probably be made to work using different libraries.
However,
from a standards view, I think your approach is incorrect and you should use a POST instead of a PUT. This requires reading both RFC-2616 (HTTP/1.1), section 9.6 on the POST request, and RFC-1630 (URL's in WWW), the section on query strings.
From the HTTP spec, section 9.6:
The fundamental difference between the POST and PUT requests is reflected in the different meaning of the Request-URI. The URI in a POST request identifies the resource that will handle the enclosed entity. That resource might be a data-accepting process, a gateway to some other protocol, or a separate entity that accepts annotations. In contrast, the URI in a PUT request identifies the entity enclosed with the request -- the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource.
From the URL's spec, page 6:
QUERY STRINGS
The question mark ("?", ASCII 3F hex) is used to delimit the boundary between the URI of a queryable object, and a set of words used to express a query on that object. When this form is used, the combined URI stands for the object which results from the query being applied to the original object.
These two combine to imply that you cannot use a PUT request in the way that you're trying to.

REST call in Java

I have a few questions about a specific REST call I'm making in JAVA. I'm quite the novice, so I've cobbled this together from several sources. The call itself looks like this:
String src = AaRestCall.subTrackingNum(trackingNum);
The Rest call class looks like this:
public class AaRestCall {
public static String subTrackingNum (Sting trackingNum) throws IOException {
URL url = new URL("https://.../rest/" + trackingNum);
String query = "{'TRACKINGNUM': trackingNum}";
//make connection
URLConnection urlc = url.openConnection();
//use post mode
urlc.setDoOutput(true);
urlc.setAllowUserInteraction(false);
//send query
PrintStream ps = new PrintStream(urlc.getOutputStream());
ps.print(query);
ps.close();
//get result
BufferedReader br = new BufferedReader(new InputStreamReader(urlc
.getInputStream()));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line=br.readLine())!=null) {
sb.append(line);
}
br.close();
return sb.toString();
}
}
Now, I have a few questions on top of the what is wrong with this in general.
1) If this rest call is returning a JSON object, is that going to get screwed up by going to a String?
2) What's the best way to parse out the JSON that is returning?
3) I'm not really certain how to format the query field. I assume that's supposed to be documented in the REST API?
Thanks in advance.
REST is a pattern applied on top of HTTP. From your questions, it seems to me that you first need to understand how HTTP (and chatty socket protocols in general) works and what the Java API offers for deal with it.
You can use whatever Json library out there to parse the HTTP response body (provided it's a 200 OK, that you need to check for, and also watch out for HTTP redirects!), but it's not how things are usually built.
If the service exposes a real RESTful interface (opposed to a simpler HTTP+JSON) you'll need to use four HTTP verbs, and URLConnection doesn't let you do so. Plus, you'll likely want to add headers for authentication, or maybe cookies (which in fact are just HTTP headers, but are still worth to be considered separately). So my suggestion is building the client-side part of the service with the HttpClient from Apache commons, or maybe some JAX-RS library with client support (for example Apache CXF). In that way you'll have full control of the communication while also getting nicer abstractions to work with, instead of consuming the InputStream provided by your URLConnection and manually serializing/deserializing parameters/responses.
Regarding the bit about how to format the query field, again you first need to grasp the basics of HTTP. Anyway, the definite answer depends on the remote service implementation, but you'll face four options:
The query string in the service URL
A form-encoded body of your HTTP request
A multipart body of your HTTP request (similar to the former, but the different MIME type is enough to give some headache) - this is often used in HTTP+JSON services that also have a website, and the same URL can be used for uploading a form that contains a file input
A service-defined (for example application/json, or application/xml) encoding for your HTTP body (again, it's really the same as the previous two points, but the different MIME encoding means that you'll have to use a different API)
Oh my. There are a couple of areas where you can improve on this code. I'm not even going to point out the errors since I'd like you to replace the HTTP calls with a HTTP client library. I'm also unaware of the spec required by your API so getting you to use the POST or GET methods properly at this level of abstraction will take more work.
1) If this rest call is returning a JSON object, is that going to get
screwed up by going to a String?
No, but marshalling that json into an obect is your job. A library like google gson can help.
2) What's the best way to parse out the JSON that is returning?
I like to use gson like I mentioned above, but you can use another marshal/unmarhal library.
3) I'm not really certain how to format the query field. I assume
that's supposed to be documented in the REST API?
Yes. Take a look at the documentation and come up with java objects that mirror the json structure. You can then parse them with the following code.
gson.fromJson(json, MyStructure.class);
Http client
Please take a look at writing your HTTP client using a library like apache HTTP client which will make your job much easier.
Testing
Since you seem to be new to this, I'd also suggest you take a look at a tool like Postman which can help you test your API calls if you suspect that the code you've written is faulty.
I think that you should use a REST client library instead of writing your own, unless it is for educational purposes - then by all means go nuts!
The REST service will respond to your call with a HTTP response, the payload may and may not be formatted as a JSON string. If it is, I suggest that you use a JSON parsing library to convert that String into a Java representation.
And yes, you will have to resort to the particular REST API:s documentation for details.
P.S. The java URL class is broken, use URI instead.

Setting content length of an HTTP POST request

I am trying to make a Http POST request using apache HTTP client. I am trying to copy contents of an HTTP POST request (received at my application) to another HTTP POST request (initiated from my application to another URL). Code is shown below:
httpPost = new HttpPost(inputURL);
// copy headers
for (Enumeration<String> e = request.getHeaderNames(); e.hasMoreElements();) {
String headerName = e.nextElement().toString();
httpPost.setHeader(headerName, request.getHeader(headerName));
}
BufferedInputStream clientToProxyBuf = new BufferedInputStream(request.getInputStream());
BasicHttpEntity basicHttpEntity = new BasicHttpEntity();
basicHttpEntity.setContent(clientToProxyBuf);
basicHttpEntity.setContentLength(clientToProxyBuf.available());
httpPost.setEntity(basicHttpEntity);
HttpResponse responseFromWeb = httpclient.execute(httpPost);
Basically, I am trying to implement a proxy application which will get a url as parameter, froward the request to the URL and then serve pages etc in custom look and feel.
Here request is HttpServletRequest. I am facing problem in setting content length. Through debugging I found out that clientToProxyBuf.available() is not giving me correct length of input stream and I am getting Http error 400 IE and Error 354 (net::ERR_CONTENT_LENGTH_MISMATCH): The server unexpectedly closed the connection in chrome.
Am I doing it wrong? Is there any other way to achieve it?
The available() function doesn't provide the actual length of the content of the stream, rather
Returns the number of bytes that can be read from this input stream without blocking. (From javadoc)
I would suggest you to first read the whole content from the stream, and then set that to the content, rather than passing the stream object. That way, you will also have the actual length of the content.
It was rather simple and very obvious. I just needed to get content length from header as:
basicHttpEntity.setContentLength(Integer.parseInt(request.getHeader("Content-Length")));

Removing oauth_token from request header in Scribe

We're trying to connect with another company's custom API which uses two-legged OAuth to authenticate a request and send us a response.
At the moment the code we have is sending a request but it's not being authenticated at the other end and so sending a UNAUTHORISED response.
The steps we have investigated so far:
Connected to the remote site using an OAuth implementation in python using the same credentials.
Asked the other company to compare our OAuth request with another that succeeds to see if there is a anything missing in ours.
After the second point above, the only difference between our request and another working request is that the oauth_token parameter is present in our request and not in others. Furthermore, he said they have an oauth_body_hash_value in most of their requests but that's not present in ours - although they do get working requests without it.
Is there a way to remove the oauth_token parameter in Scribe? Alternatively, is the oauth_body_hash_value always needed? Can a request work without?
I've included the code below, I am completely new to OAuth so please feel free to tell me if there's something else that's wrong.
Note that the TestAPI.class extends DefaultAPI10a and just returns "" for all three required methods.
public class TestImporter {
private static final String REQ_URL = "http://test.com/";
private static final String KEY = "KEY";
private static final String SECRET = "SECRET";
// test variables
private static final String VAR1 = "Test123";
public static void main(String[] args) {
OAuthService service = new ServiceBuilder()
.provider(TestAPI.class)
.apiKey(KEY)
.apiSecret(SECRET)
.build();
Token token = new Token("", "");
OAuthRequest request = new OAuthRequest(Verb.GET, REQ_URL + VAR1 + "/");
service.signRequest(token, request);
Response response = request.send();
System.out.println(response.getBody());
}
}
Regarding your own answer seems that what you want to do is put the signature in the querystring and not use the Authorization header.
This, though valid is not recommended. Anyway if you really need to do it, there's a way of creating the OAuthService to "sign" in the querystring:
ServiceBuilder()
.provider(TestAPI.class)
.apiKey(KEY)
.apiSecret(SECRET)
.signatureType(SignatureType.QueryString)
.build();
Assuming their implementation is not broken, it should not matter that you have 'extra' OAuth headers included. Having said that, the oauth_token header is not optional (I assume you are communicating using OAuth 1.0). This header should contain the access token for the User. In your example you show this token as being blank, which is quite odd!
Now assuming for some reason that it is valid to send blank 'usernames' to this third party system, you will want to make sure that your OAuth signature is matching on both sides (yours and the other companies). Use a protocol sniffer to capture the value of the oauth_signature header, then ask your third party to verify that they generate a signature which is the same. If not then you probably have a signature hashing problem.
It turns out that when we thought we were sending a fully formed HTTP GET request, we weren't.
The library was adding all of the information to the header (where we were getting our information from), but not adding any oauth information to the request Url. I can only assume it's to do with us using two-legged authorisation (hence the empty Token).
By copying the map of oAuthParameters into queryStringParameters, it then allowed the Url to be formed correctly.

Categories

Resources