Calling WCF from android over https with credentials - android

I am trying to call my RESTful WCF service over https on Android. I keep getting a 401: unauthorized error whenever I make the call. The other parts of my code work, ive tested it locally.
Here is the pertinent code:
// http scheme
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// https scheme
schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443));
credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
new UsernamePasswordCredentials("user", "pass"));
clientConnectionManager = new ThreadSafeClientConnManager(params, schemeRegistry);
context = new BasicHttpContext();
context.setAttribute("http.auth.credentials-provider", credentialsProvider);
HttpGet request = new HttpGet(SERVICE_URI + URL1 + EID);
request.setHeader("Accept", "application/json");
request.setHeader("Content-type", "application/json");
DefaultHttpClient client = new DefaultHttpClient(clientConnectionManager, params);
client.setCredentialsProvider(credentialsProvider);
HttpResponse response = client.execute(request, context);
HttpEntity responseEntity = response.getEntity();
EasySSLSocketFactory uses an implementation of X509TrustManager. I know that code works as well. Can someone please provide some advice. Nothing I have found works correctly.

Turns out, HttpClient doen't support NTLM authentication out of the box (im using IIS with windows auth). This link gave me everything I needed. Just copy and paste and forget about it.
http://hc.apache.org/httpcomponents-client-ga/ntlm.html

Related

Android Cannot POST /api response

I am trying to do HTTP post request in a REST backend. The URL for the backend is using SSL therefore I have also added the necessary code to handle that. But I got the following response:
Cannot POST /api
Here is my code:
protected String doInBackground(String... args) {
try {
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
DefaultHttpClient client = new DefaultHttpClient();
SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
registry.register(new Scheme("https", socketFactory, 443));
SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());
HttpPost post = new HttpPost("https://test-api.smart-trial.dk/api");
List <NameValuePair> nvps = new ArrayList <NameValuePair>(2);
nvps.add(new BasicNameValuePair("path[pathwayId]","5566e151817a62021b1ea809"));
nvps.add(new BasicNameValuePair("formData[firstname]","Name"));
nvps.add(new BasicNameValuePair("formData[lastname]","XXX"));
nvps.add(new BasicNameValuePair("formData[email]","example#mail.com"));
post.addHeader("Referer" ,"https://myurl.com/api");
post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
//DefaultHttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(post);
HttpEntity entity = response.getEntity();
if (entity != null) {
// get the response content as a string
String stringResponse = EntityUtils.toString(entity);
Log.d("Response", stringResponse);
}
Anything wrong in the code ? Or at least why do I get that response.
EDIT
I also have some rules for the paramaters.
"The post should be done with x-www-form-urlencoded body parameters"
I think more or less I over that by using post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8)); which x-www-form-urlencoded.
Parameters:
pathwayId (should be located in path)
firstname (should be located in formData)
lastname (should be located in formData)
email (should be located in formData)
Referer (Should be located in Header)
Sounds like your server is not configured to allow POST requests to that URL. But you need a way to verify that.
If you don't already have a REST testing plugin for your browser, find a plugin that will allow you to enter POST request data, download it and install it.
Then duplicate the POST data in the browser plugin, submit the request and view the response from the server.
At least this should help you figure out if the problem is in the app or in the server.

javax.net.ssl.sslpeerunverifiedexception no peer certificate

I am trying to insert a record into MySQL by posting data to a PHP server from an Android app. I have added the INTERNET permission to AndroidManifest.xml
I get javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
Android code
private void senddata(ArrayList<NameValuePair> data)
{
try
{
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("https://10.0.2.2/insert222.php");
httppost.setEntity(new UrlEncodedFormEntity(data));
HttpResponse response = httpclient.execute(httppost);
}
catch (Exception e) {
// TODO: handle exception
Log.e("log_tag", "Error: "+e.toString());
}
}
Can anyone help?
Warning: Do not implement this in production code you are ever going to use on a network you do not entirely trust. Especially anything going over the public internet. This link gives more correct answer. Here is an implementation using SSL.
Your problem is you are using DefaultHttpClient for https(secure url).
Create a custom DefaultHttpClient
public static HttpClient createHttpClient()
{
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
HttpProtocolParams.setUseExpectContinue(params, true);
SchemeRegistry schReg = new SchemeRegistry();
schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params, schReg);
return new DefaultHttpClient(conMgr, params);
}
Than change your code as follows:
HttpClient httpclient = createHttpClient();
HttpPost httppost = new HttpPost("https://10.0.2.2/insert222.php");
httppost.setEntity(new UrlEncodedFormEntity(data));
HttpResponse response = httpclient.execute(httppost);
Have a look at here if you have problems
It should work.
I had this issue with an IIS 8 server. In the https binding, I had to uncheck the checkbox labeled "Require Server Name Indication." Once I unchecked it, I quit getting the error.
I have to say all trusted certificates (trusted by authorized centres such as COMODO, Symantec, etc.) have to be work in any case. If your app recieves such javax.net.ssl.SSLPeerUnverifiedException: No peer certificate using bought certificate you give something wrong on server side.
To test use openssl s_client -connect example.com:443 command to get inner information about certificate your app recieve.
In may case my nginx-server sent wrong certificate in some cases.

Android SSL httpGet error 500 server denied the URL

I am trying to start a connection with a microsoft exchange server web access portal. The idea is my program initially opens a web view, and then continually refreshes the page using a BroadcastReceiver. I am aware that ordinarily, exchange web-based email access can be done through a protocol, but I'm trying this anyhow. The timing for the refresh works fine, but the problem is that although I open the connection with a WebView, I'm then doing the refresh with an HttpClient. I am passing the cookies after login from the WebView to the HttpClient successfully, and opening the connection for SSL, yet the web server is kicking back. This works fine in a browser, so I'm kinda lost.
EDIT: Ok, this is a more basic HTTP request question. All of the code that handles the httpGet is setup in the constructor. I don't even make a new HttpClient. Now, This is a BroadcastReceiver, and it responds to a timed message every 60 seconds or so to make the request, but every time the code finishes, the thread seems to die, and every time the timer goes off, the blank constructor is called. When coding an http GET request like this, do I need to be recreating the HttpClient every time? or is my using static variables that hold their value an ok way of doing it? The URL and cookies survive from one call to the next. What else am I missing? The very first call to this thing doesn't seem to work either, so I still think it's that I'm doing SSL wrong. Again, this site works just fine in a web browser, so I'm not emulating the request properly.
This is the constructor code:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
// RESTORE THE COOKIES!!!
cookieJar = new BasicCookieStore();
localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieJar);
cookie = extras.getString("cookies");
String[] cookieCutter = cookie.split(";");
for (int i=0; i < cookieCutter.length; i++)
{
String[] values = cookieCutter[i].split("=");
BasicClientCookie c = new BasicClientCookie(values[0], values[1]);
c.setDomain(MAIL_WEB_SERVER);
cookieJar.addCookie((Cookie)c);
}
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
// Create local HTTP context
SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", socketFactory, 443));
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
ThreadSafeClientConnManager mgr = new ThreadSafeClientConnManager(params, registry);
httpClient = new DefaultHttpClient(mgr, params);
httpClient.setCookieStore(cookieJar);
// Set verifier
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
And this is the refresh code:
BasicCookieStore cookies = (BasicCookieStore)localContext.getAttribute(ClientContext.COOKIE_STORE);
HttpGet httpGet = new HttpGet(url);
HttpResponse response = httpClient.execute(httpGet, localContext);
So where does this leave me? I get a Error Code: 500 Internal Server Error. The server denied the specified Uniform Resource Locator (URL). Contact the server administrator. (12202)
I am moving the cookies over, and accepting all certificates...is there anything else from a browser session with an SSL connection and a login that I need to be passing along for the httpGet request?

Make execute() of HttpDefaultClient very slow

I have massive performance problems with the execute method of the execute() method of the HttpDefaultClient.
I'm currently using this to post data to a Server, receiving JSON and deserialize the data. A call takes 8s to 30s on my phone. If I switch to Wifi (it's pretty fast, the same call takes 300ms on my PC) it takes 3s to 8s. At least 90% of that time is spend in the execute method.
Is use this code:
HttpPost post = new HttpPost(DEST_URL);
HashMap<String, String> params = req.getPostParams();
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
for (String key : params.keySet()) {
nameValuePairs.add(new BasicNameValuePair(key, params.get(key)));
}
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
post.setHeader(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
HttpResponse response = httpClient.execute(post); // very slow!
return response;
We also develop an iOS app which is able to do the same within 1 to 2s. Is there a quicker way for http (https in the future)?
Creating the client like this:
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
final SSLSocketFactory socketFactory = SSLSocketFactory
.getSocketFactory();
socketFactory
.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", socketFactory, 443));
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
HttpClient client = new DefaultHttpClient(params);
Using: HTC Wildfire, Android 2.2.1
codes above works fine.
if i create an httpclient the following way:
DefaultHttpClient httpClient = new DefaultHttpClient();
// httpclient
httpClient.getParams().setParameter(
CoreConnectionPNames.CONNECTION_TIMEOUT, mConnectionTimeOut);
httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT,
mSocketTimeOut);
for first time to post data to server and got response , it cost me 10--20 seconds.
but if i create an HttpClient following the answer above.
when first time to post data to server and got response , it cost just 4 seconds,and i think it works fine .

HTTPS In Android

I have implemented HTTP Post to post data to the backend. How do I implement HTTPS in Android (I have already configured the backend for https)?
I googled and found some solutions:
Secure HTTP Post in Android
and tried them but I do not receive any data in the backend.
Is it the correct way to implement? Is there any other method?
Below is my code snippet:
File file = new File(filepath);
HttpClient client = new DefaultHttpClient();
//String url = "http://test.....;
String url = "https://test......";
HttpPost post = new HttpPost(url);
FileEntity bin = new FileEntity(file, url);
post.setEntity(bin);
HttpResponse response = client.execute(post);
HttpEntity resEntity = response.getEntity();
Basically I am using fileentity to do a HTTPPost. Now I want to do this over https. After implementing https over at the backend I just modified http to https in the url and tested again. And it is not working.
Any idea how do i resolve this?
Thanks In Advance,
Perumal
Make sure your http client supports the SSL socket:
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
HttpParams params = new BasicHttpParams();
ClientConnectionManager manager = new ThreadSafeClientConnManager(params, schemeRegistry);
HttpClient httpsClient = new DefaultHttpClient(manager, params);
and use this client to execute your POST request:
HttpPost post = new HttpPost("https://www.mysecuresite.com");
post.setHeader("Content-Type", "application/x-www-form-urlencoded");
post.setEntity(new StringEntity("This is the POST body", HTTP.UTF_8));
HttpResponse response = httpsClient.execute(post);

Categories

Resources