I'm trying to authenticate an android client app to my server ruby on rails app which uses Devise gem. But I've tried http authentication, and post requests to authenticate, and the server just responds 200 for any given username/password.
I've already set up the config.http_authenticatable = true and the :database_authenticable at the user model...
I'll post my authenticate method so u guys can have a look on it...
public static boolean authenticate(User user, String verb) throws IOException, JSONException
{
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(verb);
CredentialsProvider credProvider = new BasicCredentialsProvider();
credProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
new UsernamePasswordCredentials(user.getMail(), user.getPassword()));
httpClient.setCredentialsProvider(credProvider);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("email", user.getMail()));
nameValuePairs.add(new BasicNameValuePair("password", user.getPassword()));
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse httpResponse = httpClient.execute(httpPost);
int statusCode = httpResponse.getStatusLine().getStatusCode();
//JSONObject resp = null;
if (statusCode < 200 || statusCode >= 300){
throw new IOException("Error");
}
return true;
}
If server is responding 200, it really sounds like server side configuration, so you should double-check your URLs are actually secured, using a desktop web browser and a tool like Fiddler so you can see everything. Pay particular attention to the Authentication headers, and the Status codes; at the least you should see a 401 from the server to start things off.
You can also turn on diagnostics for Apache HTTP on your device, and it will also dump headers and content to LOGCAT, so you can make sure everything is proceeding.
Check the WWW-Autnenticate header's contents, it will specify which schemes are accepted. The client side will re-request the URL, but it will put the Authorization header into its request.
In short, make sure your server side works outside of your application, in an environment that's easier to troubleshoot.
Client side, it looks like you are only activating BASIC authentication (everyone stop using it!), and your endpoint may only want DIGEST or NTLM or KERBEROS or any other authentication scheme than BASIC. Since it looks like you didn't set up for SSL, certainly use at least DIGEST or you have clear text issues!
Using form variables (for authentication) only works at the application level, and not the HTTP protocol level, which uses HTTP Headers (WWW-Autnenticate, Authorization) and Status codes (401, 403) for the authentication process. And again, if you aren't configuring your server (and client) for SSL-only, there will be clear text problems.
Related
I am using Apache httpClient library in my android project to send get/post requests to the server. My server is set up using apache namevirtualhost - there are multiple virtual hosts on the same server.
For those not familiar with how apache namevirtualhost works, the simple explanation is that there are multiple configurations defined in the server config, and apache uses Host request header to determine which configuration to use. When multiple hosts are defined, the first one is considered default and all requests with Host request header not explicitly matching one of the defined namevirtualhosts will be handled using the default configuration.
Now, the server I'm trying to connect to is not the default one. When my app runs and the request is made to the server, it does not go to my virtual host but instead is handled by the default one, resulting in the certificate name mismatch. (Note that I do have the correct certificates set up.)
Here's my code - copy/paste, except for the actual URL:
String targetUrl = getTargetUrl();
//this returns something like https://www.example.com/api/1/orders (without spaces, of course)
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(targetUrl);
List<NameValuePair> data = new ArrayList<NameValuePair>(1);
data.add(new BasicNameValuePair("orders", json.toString()));
data.add(new BasicNameValuePair("username", username));
data.add(new BasicNameValuePair("password", password));
post.setEntity(new UrlEncodedFormEntity(data));
HttpResponse response = client.execute(post);
This results in an error message saying that certificate name doesn't match the requested url and shows the requested url and the certificate url - the certificate url is the default one in the apache config.
I added this code right before the line to execute the request:
Header[] hds = post.getAllHeaders();
for(Header h : hds) {
Log.d("PasteneOrers", h.getName() + ": " + h.getValue());
}
to see what headers are included. Interesting, Host header is not shown. I then added this code before executing the request:
URL url = new URL(targetUrl);
post.setHeader("Host", url.getHost());
Now the above debugging output correctly shows the Host header - but it doesn't help and the request is still going to the default one.
To verify that this is not a problem with the server misconfiguration, I copied the target URL and pasted it into the browser running on the same android emulator - this works correctly and I get the right results. Hence it's definitely something in my code - but what? At this point I'm stuck. Any suggestions would be appreciated.
In the interest of others having this problem, I couldn't resolve it with apache httpclient. I switched to using HttpUrlConnection and everything worked correctly.
I know there are plenty of resources like this on the web, and the closest I've come was the answer to this question: ASP.NET Web API Authentication.
Basically, this is my requirement. Log in via android to my account on an MVC4 internet application I created (which uses SimpleMembership). It is NOT an MVC Web Api app, which seems to confuse things when looking at the various ways of achieving this.
I am attempting to use FormsAuthentication to set an authentication cookie, but I have no idea how to configure my android httpclient to actually send through this authentication cookie, or how to get MVC to save a session from my android app.
So far, this is what I've come up with on the MVC side:
[HttpPost]
[AllowAnonymous]
public bool LoginMobi(LoginModel model)
{
var membership = (SimpleMembershipProvider)Membership.Provider;
if (membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, false);
return true;
}
else return false;
}
And I use the following java in my android app (sent over an SSL connection):
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("https://mysite/api/login");
List<NameValuePair> nameValue = new ArrayList<NameValuePair>();
nameValue.add(new BasicNameValuePair("UserName", "foo"));
nameValue.add(new BasicNameValuePair("Password", "bar"));
httppost.setEntity(new UrlEncodedFormEntity(nameValue));
httppost.setHeader("Content-type", "application/json");
HttpResponse response = httpclient.execute(httppost);
// etc etc
What I haven't figured out is how to receive the authentication cookie on android and send it back with each request to controllers with the [Authorize] attribute. I'm rather new to this so please forgive my ignorance!
You are using FormsAuthentication which uses cookie to identify user for each request. You have two options here.
Use CookieStore for HttpClient. Check Android HttpClient and Cookies
OR
Combine BASIC auth and FormsAuthentication. Check Combining Forms Authentication and Basic Authentication
Hope this helps.
I'm having problems with an app that works when connecting to a remote web server, running a php script against a database. However, when I point the same app to my local web server running on my machine, things doesn't work.
Here's the code I use for connecting to the remote web server (it needs authentication):
(All the networking code is done inside an AsyncTask class.)
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
StringBuilder authentication = new
StringBuilder().append("frankh").append(":").append("vriceI29");
result = Base64.encodeBytes(authentication.toString().getBytes());
httppost.setHeader("Authorization", "Basic " + result);
nameValuePairs.add(new BasicNameValuePair("date", date));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
is = entity.getContent();
For the connection to the local server, which doesn't use authentication, I'm commenting out these lines:
//StringBuilder authentication = new
// StringBuilder().append("frankh").append(":").append("vriceI29");
//result = Base64.encodeBytes(authentication.toString().getBytes());
//httppost.setHeader("Authorization", "Basic " + result);
However, I get two different errors, depending on how I phrase the url to the local web server.
If I use this url: "http://localhost.shoppinglistapp/fetchlist.php"
I get this error:
Error in http connectionjava.net.UnknownHostException: localhost.shoppinglistapp
If I skip the http part in the url, I get this error:
Error in http connectionjava.lang.IllegalStateException: Target host must not be null,
or set in parameters.
What am I doing wrong here? The remote server is a Linux Apache server, and the local server is IIS 7. The local server is supposed to be just for working on when I've got no or a bad internet connection, so it's not critical, but I hate not knowing why things doesn't work.
If you testing via your local emulator, you'll want to use 10.0.2.2 instead of 'localhost'.
Referring to localhost from the emulated environment
Site: http://na.leagueoflegends.com/ladders/solo-5x5
Search for a a player (example: Jaiybe)
You get redirected (in this case to: http://na.leagueoflegends.com/ladders/solo-5x5?highlight=28&page=1)
Read the content
And I want to do that in java/android.
I analyze the sites POST request when searching, result:
op:Search
player:Jaiybe
ladder_id:3
form_build_id:form-fff5e6e2569f1e15e5a5caf2a61c15e2
form_id:ladders_filter_form
Build a simple HTTP POST mixture and lets read the content...
The CODE:
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://na.leagueoflegends.com/ladders/solo-5x5");
// Add your POST METHOD attributes
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("op", "Search"));
nameValuePairs.add(new BasicNameValuePair("player", Jaiybe));
nameValuePairs.add(new BasicNameValuePair("ladder_id", "3"));
nameValuePairs.add(new BasicNameValuePair("form_build_id","form-daca6fff89cedc352ccc3f533afa3804"));
nameValuePairs.add(new BasicNameValuePair("form_id","ladders_filter_form"));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
responseBody = EntityUtils.toString(response.getEntity());
return responseBody;
And when I run it - I get so some kind of a offline page...
The number form_build_id - is constantly changing, but this was no problem, to use still the same one, and also If I would like to "test" if this could be the problem, I have no Idea how would I...
OR: Is there any other - FAST - way how to get same results?
What is strange is that the "error" site source code that I get on android is different as if I run the same on my PC (Win7, Eclipse, Java) or in my browser. As if there would be two versions of offline sites - for mobile and for PC - but my question: HOW WOULD the server know that the code runs on a Android device? Is there a way how to set this up in HttpClient?
form_build_id:form-fff5e6e2569f1e15e5a5caf2a61c15e2
This is an auto generated token that is valid for a certain time period. This is probably the source of your problem and the reason the token exists in the first place (to prevent post spams).
As this token does not seem session based, you could actually use an HTTP Get on the page that generates the form and parse out the generated token each time for your HTTP Post.
About OS detection, browsers usually provide information about the OS using the HTTP User-Agent header.
I have an android app that is working fine when connected to a production web server. A development server was created for testing future releases. It's an IIS server that's locked down with username/password.
I am trying to use httpclient.getCredentialsProvider() to send a username and password so I can authenticate to the page before doing anything else but it doesn't seem to be working correctly so I assume I am missing some code or doing something wrong.
I tried messing with the credentials and sending the port and full url but that didn't work either so I just switched it to null and -1 which from what I gather means it should work on any site any port, but every way I tried still got the same result of not authenticating.
Here is what I have now.
HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 10000);
HttpConnectionParams.setSoTimeout(httpParams, 10000);
DefaultHttpClient httpclient = new DefaultHttpClient(httpParams);
httpclient.getCredentialsProvider().setCredentials(new AuthScope(null,-1), new UsernamePasswordCredentials("someusername", "somepassword"));
HttpPost httpost = new HttpPost("someURL");
Other non-relevant code to set Name Value Pair for posting
Then
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nvps, HTTP.UTF_8);
httpost.setEntity(formEntity);
HttpResponse response = httpclient.execute(httpost);
IIS supports HTTP authentication methods like Basic, Digest and Integrated. The problem is that all of them are hardwired to Windows accounts. This means that you need a Windows user on your server for every account you want to HTTP-auth enable.
Having the ability to do plain Basic Authentication agains account stored e.g. in a database would be very handy for a range of situations like web applications, (WCF) web services, REST services, Silverlight service backends etc.
enter link description here