I am trying to get some data (json data -> restful server) from a HTTPS server with basic authentification using the Apache httpclient. The SSL certificate is selfsigned.
The server is responding very well to a browser call and also when using curl.
However using the java Apache httpclient, that's another story.
Client side :
The basic authentification is working : the server sends me 401 errors if forget the authorization header or if I set the wrong base64 encoded login:password.
The https/SSL part is working : I am successfully getting data from online restful json server but sadly no way to find an online restful json server with basic authentification for testing purpose...
try {
CloseableHttpClient httpClient = null;
try {
httpClient = HttpClients.custom()
.setSSLSocketFactory(new SSLConnectionSocketFactory(SSLContexts.custom()
.loadTrustMaterial(null, new TrustSelfSignedStrategy())
.build()
)
)
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.build();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
}
HttpGet getRequest = new HttpGet("https://localhost:5050/getdata");
getRequest.addHeader("Accept", "*/*");
getRequest.addHeader("Authorization", "Basic UBJ0aHVyOmFo0XElYHU=");
HttpResponse response = httpClient.execute(getRequest);
Debugging is telling me :
Caused by: org.apache.http.ProtocolException: The server failed to respond with a valid HTTP response
True! It's not a valid HTTP response that I would like to get, it's a valid HTTPS response!
I guess that I am missing something...
Solved!
The error was from the server side : my response did not include any headers....
httpclient seems to like well made responses from a server. That's not true for a browser or for curl : garbage they can receive , display they will !
Related
I‘m working on an application that sends data to an azure event hub. This is similar to the blog post here:http://sreesharp.com/send-events-from-android-app-to-microsoft-azure-event-hubs/
However, I updated the connection code to use OkHttp:
public void sendMessageOkHttp(String dataPacket, String connectionString, String sasKey){
// Instantiate the OkHttp Client
OkHttpClient client = new OkHttpClient();
// Create the body of the message to be send
RequestBody formBody = new FormBody.Builder()
.add("message", dataPacket)
.build();
// Now create the request and post it
Request request = new Request.Builder()
.header("Authorization", sasKey)
.url(connectionString)
.post(formBody)
.build();
Log.i(TAG,"about to send message");
// Now try to send the message
try {
Log.i(TAG,"sending message....");
Response response = client.newCall(request).execute();
Log.i(TAG,"message sent");
Log.i("Azure Response",String.valueOf(response.message()));
// Do something with the response.
} catch (IOException e) {
e.printStackTrace();
}
}
However this returns a response from the event hub "Unauthorized". The sas key I am using is for a shared access policy that I created with send and listen permissions. It is the primary key.
What am I doing wrong here? The Azure documentation doesnt really help me in this case because it focused on using the Azure Java libraries that are not Android compatible (i.e. they require Java 1.8)
It's not the SAS Key you send in the Authorization header, it's the SAS Token. Here are like 5 or six different languages for generating the SAS Token from the key: https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-sas-overview
This question already has answers here:
Apache HttpClient Digest authentication
(4 answers)
Closed 4 years ago.
When I try to connect to a webserver using DIGEST authentification, the connection will be refused (401, Not Authenticated). The Answers I could find related to this topic where mostly deprecated, so I wanted to start a discussion about resolving this problem with the current version:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.4.1</version>
</dependency>
The following code allows to set credentials and connect to my target rest-service using Apache HttpClient. The credentials I am using are correct, so there must be something wrong with my configuration of the credentials or the way I'm using the HTTPClient.
HttpGet getArticles = new HttpGet("http://myurl.xx/api/");
Registry<AuthSchemeProvider> authSchemeRegistry =
RegistryBuilder.<AuthSchemeProvider>create().register(AuthSchemes.DIGEST,new DigestSchemeFactory()).build();
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
new AuthScope("http://myurl.xx/api/",80),
new UsernamePasswordCredentials(username,pw));
CloseableHttpClient client = HttpClients.custom()
.setDefaultAuthSchemeRegistry(authSchemeRegistry)
.setDefaultCredentialsProvider(credentialsProvider).build();
try {
CloseableHttpResponse response = client.execute(getArticles);
logger.info(String.valueOf(response.getStatusLine().getStatusCode()));
} catch (IOException e) {
logger.error(e.getMessage(),e);
}finally {
try {
client.close();
} catch (IOException e) {
logger.error(e.getMessage(),e);
}
}
This will return
HTTP/1.1 401 Unauthorized
I'm not an expert with digest auth but I know you have to connect twice, because the servers will send you some auth data in the first place. But I believe that, when I register DIGEST as the AuthentificationScheme, this should be handled automatically?
When I check the Client
client.authSchemeRegistry says:
{digest=org.apache.http.impl.auth.DigestSchemeFactory#481a996b}
So it's successfully registered.
It may or may not be the reason, but the scope of credentials is wrong. The AuthScope constructor takes a host name, not a URL as the first parameter.
credentialsProvider.setCredentials(
new AuthScope("myurl.xx",80),
new UsernamePasswordCredentials(username,pw));
I want to save a message in a text file on an android phone onto a hosted web server like bluehost of which I have a username and password. I want to store the file in an arbitrary directory on the server.
What are the general strategies that this could be accomplished? I want to use the HTTP protocol, is that a good idea? Is there a better way?
You can try to POST that string to the server:
// Create a new HttpClient and Post Header
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://www.example.com");
try {
// Add your data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("yourVarName", stringVar);
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
return (response.getStatusLine().getStatusCode() == 200 || response.getStatusLine().getStatusCode() == 204);
} catch (ClientProtocolException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
Transmit a file from an android phone to hosted web space
You import the JSCH jars into your Android application, then you load up the JSCH manager classes and use the defined functions to transmit or receive files between an android phone and hosted webspace.
Run a command over SSH with JSch
JSCH has FTP functionality where you can transmit from phone to hosted web space and will work as long as the hosted web space is reachable by the phone. You can also do the same thing in reverse.
trying to access http://forum.worldoftanks.eu/index.php?app=members using apache HttpClient but keep getting 403. Can anyone help out?
Been fiddling with this piece as a starting point:
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpRequestBase method = new HttpGet(theUrl);
String s = httpClient.execute(method, new BasicResponseHandler());
System.out.println(s);
httpClient.getConnectionManager().shutdown();
I don't think this is related to HttpClient. I tried this
$ wget http://forum.worldoftanks.eu/index.php?app=members
--2011-08-08 23:17:52-- http://forum.worldoftanks.eu/index.php?app=members
Resolving forum.worldoftanks.eu (forum.worldoftanks.eu)... 213.252.177.21, 213.2
52.177.20
Connecting to forum.worldoftanks.eu (forum.worldoftanks.eu)|213.252.177.21|:80..
. connected.
HTTP request sent, awaiting response... 403 Forbidden
2011-08-08 23:17:56 ERROR 403: Forbidden.
with no luck.
Yet I can hit it in the browser. It might be that there is some server logic returning 403s when an appropriate browser headers aren't sent. My next step would be to use FireBug and try to replicate the request as your browser makes it.
Also, try catching the exceptino
} catch (HttpResponseException e) {
System.err.println(e.response.parseAsString());
}
Does anyone have a good example of how to do https over http (or a socket)?
The embedded java platform doesn't support https out of the box, but I'm sure it should be possible using some 3rd party libraries or source code snippets.
If anyone can point me to the correct direction I'd be very grateful
What profile are you using? MIDP comes with HTTS handler. I just checked the code. This package,
com.sun.midp.io.j2me.https
implements HttpsConnection interface.
EDIT:
I think your best bet is to find an old version of BouncyCastle JCE that works with your version of Java. BC JCE comes with this class to handle SSL,
http://www.bouncycastle.org/docs/docs1.3/org/bouncycastle/crypto/tls/TlsProtocolHandler.html
This test shows you how to make a simple HTTPS request.
http://www.java2s.com/Open-Source/Java-Document/Security/Bouncy-Castle/org/bouncycastle/crypto/tls/test/BasicTlsTest.java.htm
As bitover has said, you can use apache http components.
Simple example where https page need user credentials:
public static void main (String[] args){
HttpClient httpclient = new DefaultHttpClient();
// Note that the specified port 443 corresponds with the SSL service
((AbstractHttpClient) httpclient).getCredentialsProvider().setCredentials(
new AuthScope("www.moneytrackin.com", 443),
new UsernamePasswordCredentials("user", "password"));
// Https page to access
HttpGet httpget = new HttpGet("https://www.moneytrackin.com/api/rest/getBalance");
HttpResponse response;
try {
response = httpclient.execute(httpget);
System.out.println("State: "+response.getStatusLine().toString());
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
String result= convertStreamToString(instream);
System.out.println("Data: "+result);
instream.close();
}
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
More examples in this blog.
Apache HttpCore is what you need. See more: http://hc.apache.org/httpcomponents-core/index.html
Br,
Gabi
From what i can remember, with HttpComponents you just set the socket factory to use the SSLSocketFactory and it works; however, the SSLSocketFactory was added in Java 1.4.
Honestly, I would not think the Apache HttpComponents API would even work on the limited environment you described... you would most likely need an older version, from back when it was called HttpClient (I think) and part of the Jakarta Commons.
Good luck
JBoss netty has an example of HTTP client, you just need to add the SSlHandler in HTTPRequestHandler and HTTPResponseHandler.