I'm writing a web application that can display code smell result from the Sonarqube, but I also want it can create custom rules sometimes. Currently, I'm able to get the data from the server using HTTPClient in Java or XMLHttpRequest in Js. However, I'm really stuck on POST message to the server.
In Js, I've tried these code to log in: (the CORS has been disabled in my chrome)
request.open("POST", "http://localhost:9000/api/authentication/login?login=admin&password=admin", true);
request.send();
The response status code is 200 which is successful. However, when I try to perform some action that needs permission
request.open("POST", "http://localhost:9000/api/qualityprofiles/copy?fromKey=" + fromKey + "&toName=" + name, true);
request.send();
The result is 401, unauthorized.
After some research, I've changed my code to
var base64encodedData = ("admin:admin").toString('base64');
request.open("POST", "http://localhost:9000/api/qualityprofiles/copy?fromKey=" + fromKey + "&toName=" + name, true);
request.setRequestHeader("Authorization", "Basic " + base64encodedData);
request.send();
The response is 405, no method found.
After further research, someone mentioned the request.withCredentials should set to true. I added in, then I got CORS problem again. (with the CORS disabled)
(I'm bit confused about the Sonarqube API. The reason I'm saying this is, in my opinion, the purpose of this API is to simplify the method to play with the Sonarqube server externally. However, since it does not allow CORS, does that mean I cannot use the API on my own web page?)
Since there is no luck in Js, I switched to Java.
In Java, I ran this: (I've done login as well)
HttpPost post = new HttpPost("http://localhost:9000/api/qualityprofiles/copy?fromKey=AV7dToVK_BWPTtE1c9vU&toName=testtt");
try(CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(post);) {
System.out.println(response.getStatusLine());
}
I got:
HTTP/1.1 401
Then I change my code follow this link about Basic Authentication with the API
CredentialsProvider provider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials
= new UsernamePasswordCredentials("admin", "admin");
provider.setCredentials(AuthScope.ANY, credentials);
HttpClient client = HttpClientBuilder.create()
.setDefaultCredentialsProvider(provider)
.build();
HttpResponse response = client.execute(
new HttpPost("http://localhost:9000/api/qualityprofiles/copy?fromKey=AV7dToVK_BWPTtE1c9vU&toName=testtt"));
int statusCode = response.getStatusLine().getStatusCode();
System.out.println(statusCode);
Again, 401
In summary, my question is: How can I use Java code or Js code (preferred) to POST messages to the SonarQube server with authorization?
Appriciate for any help!
UPDATE
I'm now trying with curl, here is what I run in terminal
curl -X POST -u deb3dd4152c571bcdb7b965e1d99b23a4e5c9505: http://localhost:9000/api/qualityprofiles/copy?fromKey=AV7dToVK_BWPTtE1c9vU&toName=test_file
And I got this response, which I don't know how
{"errors":[{"msg":"The 'toName' parameter is missing"}]}
Second Update on CURL
I ran:
curl -X POST -F "fromKey=AV7dToVK_BWPTtE1c9vU;toName=test_file" -v -u deb3dd4152c571bcdb7b965e1d99b23a4e5c9505: http://localhost:9000/api/qualityprofiles/copy
Result:
* Trying ::1...
* Connected to localhost (::1) port 9000 (#0)
* Server auth using Basic with user 'deb3dd4152c571bcdb7b965e1d99b23a4e5c9505'
> POST /api/qualityprofiles/copy HTTP/1.1
> Host: localhost:9000
> Authorization: Basic ZGViM2RkNDE1MmM1NzFiY2RiN2I5NjVlMWQ5OWIyM2E0ZTVjOTUwNTo=
> User-Agent: curl/7.49.1
> Accept: */*
> Content-Length: 179
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=------------------------c22bb5dd76f44ac4
>
< HTTP/1.1 100
< HTTP/1.1 400
< Content-Type: application/json
< Content-Length: 56
< Date: Wed, 04 Oct 2017 00:43:47 GMT
< Connection: close
<
* Closing connection 0
{"errors":[{"msg":"The 'toName' parameter is missing"}]}
For anyone who got the same issue. I've got it working on Java code, Here is my code
HttpPost post = new HttpPost("http://localhost:9000/api/qualityprofiles/copy?fromKey=AV7dToVK_BWPTtE1c9vU&toName=testtt");
post.setHeader("Authorization", "Basic ZGViM2RkNDE1MmM1NzFiY2RiN2I5NjVlMWQ5OWIyM2E0ZTVjOTUwNTo=");
try(CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(post);) {
System.out.println(response.getStatusLine());
}
You may notice I've added a line which sets the header. I've done something similar before to encode my login and password to this base64 format, but they all not working somehow. This working encoded string was taking from the CURL method. (from my second update)
I've tried some online base64 encoding and decoding tool, but the result doesn't match what I got from the CURL method, So if you are struggling on this, run CURL to get your encoded header and pass it in! If anyone could explain a better version, that would be great!
Also, I'm still interested in get the Js version working. If you know the answer, please share!
This Code from C#
string url = "http://localhost:9000/api/project_badges/quality_gate?project=projectName";
HttpClient client = new HttpClient();
var byteArray = Encoding.ASCII.GetBytes("username:password");
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
string responseString = string.Empty;
var response = client.PostAsync(url, null).Result;
if (response.IsSuccessStatusCode)
{
var responseContent = response.Content;
responseString = responseContent.ReadAsStringAsync().Result;
}
I am using apache http library to build and send a multi-part http request that has a file part in the body. Here is a little sample of my request
Request POST HTTPS://hostname:9443/di/resources/upload?logonId=user1 HTTP/1.1:
Headers: Content-Type: multipart/form-data Set-Cookie: Path=/; HttpOnly TrustToken: -1000%2CCaKOjiTFmje3%2Fw0GGcw5%2BDwgxXHjHdQShQgW1QGiHYk%3D
Body: --ncFZGuKp50zCWWImlBFZjxbanSSoJt
Content-Disposition: form-data; name="File 1"; filename="SampleData_en.csv"
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Identifier,title,,,,,,,,,,,,,,
Plan: Entries (1) or ent2 (2) ,2,"Set to 1 to specify plan is for Catalog Entries, set to 2 etc .....
--ncFZGuKp50zCWWImlBFZjxbanSSoJt--
The project is that the service is based on apache wink that has a problem decoding the headers in the body which gives this kind of error
Caused by: java.lang.StringIndexOutOfBoundsException
at java.lang.String.substring(String.java:1240)
at org.apache.wink.common.internal.providers.multipart.MultiPartParser.parseHeaders(MultiPartParser.java:264)
at org.apache.wink.common.internal.providers.multipart.MultiPartParser.nextPart(MultiPartParser.java:109)
at org.apache.wink.common.model.multipart.InMultiPart.hasNext(InMultiPart.java:83)
I believe the fix would be to remove the Content-Transfer-Encoding from the body? or change it to maybe a different encoding, maybe base64.
The only problem is that I dont know how to do this using the apache library and haven't been able to find anything examples. Here is the code I am using apache to create the entity portion of my HttpPost request:
MultipartEntityBuilder reqEntity = MultipartEntityBuilder.create();
File file1 = RequestUtils.getFileBody(filePath);
FileBody fileBodyFile1 = new FileBody(file1, org.apache.http.entity.ContentType.create("application/octet-stream"),
file1 .getName());
reqEntity.addPart("File 1", fileBodyFile1);
Program is an applet designed to take some files, process them, send them through a ZipOutputStream, and upload the (usually rather large) zip file to the server. It is using Apache HttpClient 4.2.1 (and ancillary libraries). My post request is executing in a privileged space. The issue I'm having is Apache/2.2.16 (Win32) refuses to take the request. I get an error in the Apache error logs, "chunked Transfer-Encoding forbidden".
If I use wireshark to capture the connection, the request looks like:
POST /data/FileUpload.php?userId=21 HTTP/1.1
Transfer-Encoding: chunked
Content-Type: multipart/form-data; boundary=PjgV56PRG1T0eeWZNfM3Gumc8v0p8j
Host: 192.168.2.16:8000
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.2.1 (java 1.5)
10be
--PjgV56PRG1T0eeWZNfM3Gumc8v0p8j
Content-Disposition: form-data; name="ZipFile"; filename="JavaUploaderZipStream.zip"
Content-Type: application/zip
Content-Transfer-Encoding: binary
The code that executes this request is:
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpClient httpclient = new DefaultHttpClient(params);
HttpPost httpPost = new HttpPost(url);
ZipCompressionInputStream zipStream = new ZipCompressionInputStream(fileList);
MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.STRICT);
InputStreamBody uploadPart = new InputStreamBody(zipStream, "application/zip", "JavaUploaderZipStream.zip");
reqEntity.addPart("ZipFile", uploadPart);
httpPost.setEntity(reqEntity);
HttpResponse response = httpclient.execute(httpPost);
try {
HttpEntity responseEntity = response.getEntity();
EntityUtils.consume(responseEntity);
} finally {
httpPost.releaseConnection();
}
From what I can tell, Apache 2.2 is supposed to accept chunked data. I don't see any switches that reject it. It seems to be accepting the HTTP/1.1 connection. I'm at a loss as to why it just flat refuses anything I try.
I use AsyncHttpClient to create an http POST request:
AsyncHttpClient.BoundRequestBuilder reqBuilder;
reqBuilder = httpClient.preparePost(url);
reqBuilder.setBody(data);
It sometimes doesn't send content-type header and sometimes sends it as
Content-Type: text/html; charset=ISO-8859-1
which causes our request to fail at [REST API] server side.
I am at a loss to understand why it is inconsistent.
Client is created as below:
import com.ning.http.client.*;
AsyncHttpClient httpClient = new AsyncHttpClient(
new AsyncHttpClientConfig.Builder().build());
You can set headers by your self
reqBuilder.setHeader(String name, String value);
or add
reqBuilder.addHeader(String name, String value);
I try to talk to a server, by telneting to it, and send the following command through telnet terminal :
POST /%5bvUpJYKw4QvGRMBmhATUxRwv4JrU9aDnwNEuangVyy6OuHxi2YiY=%5dImage? HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 164
[SORT]=0,1,0,10,5,0,KL,0&[FIELD]=33,38,51,58,68,88,78,98,99,101,56,57,69,70,71,72,89,90,91,92,59,60,61,62,79,80,81,82&[LIST]=1155.KL,1295.KL,7191.KL,0097.KL,2267.KL
This works very fine. Now, I wish I can use HttpClient, to talk to the server, as I use telnet to talk to the server. The reason I wish to use HttpClient, instead of using raw TCP socket, is because HttpClient does support NTLM.
However, when I use POST method with NameValuePair :
new NameValuePair("[SORT]", "0,1,0,10,5,0,KL,0")
The request will become URL encoded. The server doesn't understand URL encoded request.
%5BSORT%5D: 0%2C1%2C0%2C10%2C5%2C0%2CKL%2C0
Is there any way I can avoid this? If not, what is the alternative library I can use? I wish to support NTLM as well.
As I mentioned in the other thread, this is not even valid HTTP POST. So you can't do it with default post mechanism in HttpClient. You need to make the invalid body yourself and post it.
Assuming you are using HttpClient 3, following code should work,
HttpClient httpClient = new HttpClient();
PostMethod method = new PostMethod(url);
String badFormPost = "[SORT]=0,1,0,10,5,0,KL,0&[FIELD]=33,38,51,58,68,88,78,98,99,101,56,57,69,70,71,72,89,90,91,92,59,60,61,62,79,80,81,82&[LIST]=1155.KL,1295.KL,7191.KL,0097.KL,2267.KL";
RequestEntity entity = new StringRequestEntity(badFormPost,
"application/x-www-form-urlencoded", "UTF-8");
method.setRequestEntity(entity);
method.setContentChunked(false);
httpClient.executeMethod(method);
...
It's getting URL encoded because your request formed with HTTPClient may be a GET request instead of a POST and is missing this header:
Content-Type: application/x-www-form-urlencoded
Look for the HTTPClient setting to set the Content-Type header correctly and make sure your request is a POST, not a get and you should be golden.