I am using Spring for Android in a project and I need to manage the cookie store/manager. I am able to add cookies to any request by using an implementation of ClientHttpRequestInterceptor, but I would like to remove some of these when sending a request.
To be more specific, the problem I am facing is that, for Froyo, the implementation specific in Spring (with DefaultHttpClient) adds automatically to headers the cookies from CookieStore - that even if I am setting explicitly the headers. But I would like to manage these cookies myself (either remove some of them, or update their values). While for Gingerbread above (Spring implementation is done with HttpURLConnection) the cookies are added only if I am doing it myself - however I am not that sure as I don't see Spring setting any CookieHandler, but the bottom line is that I don't see them when performing a request or I can see them updated. So the issue is more specific to Froyo.
The work-around is to reset the connection factory; something like:
protected void resetCookieStoreForTemplate(RestTemplate template) {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.FROYO) {
template.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
}
}
Underneath, that seems to recreate the DefaultHttpClient and will use a new CookieStore. But that seems to me a bit ugly.
To wrap up, my question would be: does Spring for Android provide some method to expose some API for Cookie management? Just the way RestTemplate exposes some abstractions for connectivity, connection factory, message converters and so on, I would be very happy to have some abstraction for cookie management.
I've not used Spring myself but from what I've read about it, it follows the official advice and switches HTTP clients based on API version (which is quite clever, if seriously over-engineered for my liking). When using HTTPUrlConnection, as you mentioned, Spring probably doesn't change the CookieHandler. You should be seeing in-memory cookie handling, so everything should work for requests in the same app run but the cookies would be wiped when you close the app. Can you confirm this is what you're seeing?
If so, all you have to do is create a new CookieManager instance, passing it a custom CookieStore and null for the CookiePolicy to use the default.
It's unfortunate that a persistent store isn't built-in but it's not particularly difficult to write one either.
Edit: See here for a CookieStore that uses SharedPreferences (haven't tested it myself).
The ClientHttpRequestInterceptor class is a good approach when you need to pass common headers for all requests such as setting up content type, authorization etc. As far as I understood you want to pass some cookie values for specific request.
You could also achieve this via HttpEntity and HttpHeaders class.
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Cookie", "name=" + value);
HttpEntity requestEntity = new HttpEntity(null, requestHeaders);
ResponseEntity response = restTemplate.exchange(
"http://server/service?...",
HttpMethod.GET,
requestEntity,
Response.class);
Spring rest template does not provide any off the self solution for managing cookies. The class CookieHandler is provided by Apache not part of spring. Rest template is just a basic solution for managing request response with compare to spring core.
Related
Is there a simple way to make sure the HttpClient does not send the cookies during a request, without removing all cookies.
By doing:
httpClient.getCookieStore().clear();
cookies are not sent, which is good.
But for other requests (where I need those cookies), I don't want to fetch new cookies again.
You can try to set the Cookie header of the request manually for that particular request
request.setHeader("Cookie","");
Edited:
So if is that not working an other approach could be to try to add an empty cookie store to that HttpClient instance, so theoretically you will have an empty cookiestore
// Create a local instance of cookie store
CookieStore cookieStore = new BasicCookieStore();
// Add the created cookieStore to the http client instance
httpClient.setCookieStore(cookieStore);
My response is based on assumption that you are using Apache HttpClient version 4.x.
By default HttpClient 4.x introduces two protocol interceptors to the protocol processing pipeline responsible for HTTP state management: RequestAddCookies and ResponseProcessCookies. What you want is to remove RequestAddCookies while leaving ResponseProcessCookies in place.
This is how this can be done with HttpClient 4.3
CloseableHttpClient httpclient = HttpClients.custom()
.disableCookieManagement()
.addInterceptorFirst(new ResponseProcessCookies())
.build();
There are other ways to achieve the same result such as using a custom protocol interceptor that removes cookie headers from all outgoing requests, but removal of RequestAddCookies is the most efficient.
I'm trying to implement a RESTful web service using Spring. I've set up Spring Security to work on the links that apply to the REST service. I make calls to this web service from an Android application. What I've done now is connect to it using Basic Authentication. What I'm struggling with is finding decent information about how secure this really is. I figure I should at least be making these calls through SSL or something no?
My code on the Android client that calls the REST client
public MyClass callRest() {
final String url = "http://10.0.2.2:8080/myservice/rest/getSomething";
HttpAuthentication authHeader = new HttpBasicAuthentication(username,
password);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setAuthorization(authHeader);
requestHeaders.setAccept(Collections
.singletonList(MediaType.APPLICATION_JSON));
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(
new MappingJacksonHttpMessageConverter());
try {
ResponseEntity<MyClass> response = restTemplate.exchange(url,
HttpMethod.GET, new HttpEntity<Object>(requestHeaders),
MyClass.class);
return response.getBody();
} catch (HttpClientErrorException e) {
return new MyClass();
}
}
So what I've put in my Spring Security config right now:
<http auto-config='true'>
<intercept-url pattern="/rest/**" access="ROLE_USER"
requires-channel="https" />
</http>
I can't figure out where to go from there, because now the connection doesn't work anymore of course because of the https. I can't seem to find decent examples of how to figure this out using the Resttemplate.
Any help?
HTTP Basic Authentication is reasonably safe when used over HTTPS since the user and password fields are sent over an encrypted connection so they are much less vulnerable to man-in-the-middle attacks. There are some interesting points here: Securing an API: SSL & HTTP Basic Authentication vs Signature
In my opinion, if you are making a API with access to user's sensitive data (i.e. bank account details, credit card numbers, email addresses and passwords) then you may want a more secure approach because HTTP Basic Authentication is succeptible to brute force attacks as it is always available (unless you build in deterrents such as maximum retries etc.) If your API is for a game or basic business data then there should be less attraction for a hacker to spend the time on it.
Does your server support HTTPS - often you need to pay extra for a HTTPS certificate or you have to use a shared once which give you a subdomain on a shared HTTPS domain - i.e. https//your-site.your-hosting-provider.com/. You need to check this perhaps.
UPDATE 1: Your problem appears to be with your server and not with your program. Check out this blog post for information about how to set up HTTPS on your Tomcat Server. You need to do this before you can use HTTPS from your Spring application - looking at your code, there doesn't seem to be a problem other than your server.
Also try this.
UPDATE 2 Once you have access, you will then need to trust the certificate on the Android device (or your Java installation if you were making a desktop/web application). It needs to be trusted because you created it yourself rather than a CA authority. See this answer: Trusting all certificates using HttpClient over HTTPS (Not the part about trusting all certificates - this can be dangerous).
So basically i need my android app to connect to a web service using a url as such
"http://username:password#0.0.0.0" aka basic authentication.
obviously the username and password are checked by the web app before allowing access and otherwise doesn't allow the request.
my issue is that all the methods i try always say unauthorised (response code 401) regardless of what combination of classes and methods ive used to try and connect to the the url.
The web app in question is designed to return things only is un/pw clears otherwise it returns nothing, the web app and un/pw etc have all be checked and cleared.
so does anyone no the correct way to send a request to a url like that and have it work correctly?
android api8 btw
UPDATE
Turns out my issue is due to the web app using NTLM windows authentication which is not supported directly by androids/apache http library, investigating appropriate workarounds now
Here's some code form a really old project of mine. I used basic auth for some web service, and this worked at the time. I'm not sure if there are updated api's since then (this was Android 1.6), but it should still work.
HttpGet request = new HttpGet();
request.setURI(new URI(url));
UsernamePasswordCredentials credentials =
new UsernamePasswordCredentials(authUser, authPass);
BasicScheme scheme = new BasicScheme();
Header authorizationHeader = scheme.authenticate(credentials, request);
request.addHeader(authorizationHeader);
Basically, Basic HTTP auth is a simple hash of the user and password. The browser allows you to stuff these values in the url, but it actually does the work of adding the basic auth header to your request.
I want to know whether it is possible to create an Android application to communicate with a session bean and invoke a method. if so can anybody explain how? or else can i invoke that method in the EJB with a JSP/servelet and call the JSP/Servelet with Android clients.. examples are highly appreciate
Thanks !!!
It is possible to communicate with Servelet in Android using HttpClient, HttpPost and HttpGet classes in android..
It is in theory relatively simple. Servlets can be configured by web.xml or #WebServlet annotation to get executed on a certain request URL. On a HTTP GET request the doGet() method will be executed. On a HTTP POST request, the doPost() method will be executed. The business logic which the servlet executes can depend/rely on the presence of HTTP request parameters and/or the request URI pathinfo.
All you need to do is to fire a HTTP request with the right URL and/or the right request parameters and/or the right pathinfo to let the servlet execute the desired job.
The basic Java API offers the java.net.URL and java.net.URLConnection for this. A simple HTTP GET request can be executed as follows:
InputStream response = new URL("http://example.com/servleturl?foo=bar&bar=foo").openStream();
// ...
Firing HTTP POST requests is a bit more complex. It can be done with java.net.URLConnection as outlined in this mini-tutorial, but Android also ships with Apache HttpComponents Client which allows firing and handling HTTP requests with less lines of code and more self-explaining code.
On http://androidsnippets.org you can find a lot of examples with HttpClient.
In my Android app, each activity is filled with data from an xml file which is somewhere on the web. The website providing these files has a login mechanism, that works with cookies.
I know how to make a HTTP Request to the login page and receive a cookie. What I don't know is, how I can store it to re-use it in both other activities AND when the app is started the next time. The cookie is valid for a year, so the user of my app should log in once and then never again for a whole year.
How do I do that? I googled a lot, but either I used the wrong keywords or there are no simple solutions on the internet. I hope somebody here can help me.
Best regards and thanks in advance, Jan Oliver
Use a CookieSyncManager to store your cookie value. It can persist across application starts.
Beware of using CookieSyncManager inside of WebViewClient#shouldInterceptRequest on KitKat. It will deadlock.
EDIT
CookieSyncManager was deprecated in API 21:
This class was deprecated in API level 21. The WebView now
automatically syncs cookies as necessary. You no longer need to create
or use the CookieSyncManager. To manually force a sync you can use the
CookieManager method flush() which is a synchronous replacement for
sync().
It looks like Android is using the default in memory implementation so you will need to create your own persistent cookie store.
This Java Tutorial outlines creating your own persistent store taking advantage of the default implementation.
http://download.oracle.com/javase/tutorial/networking/cookies/custom.html
The sample has two todo's for storage (read/write) For storage I would just use SharedPreferences to store just the session cookie that you need and not persist any others.
The sample uses a shutdown hook which is not what you want in Android. In place of run() and the hook I would just have a new public method persist() that saves what you want, though that requires that you persist() the store by hand.
Given that you only have one or two cookies that matter you could save them in the add(...)
After you make your http call, you can grab the cookies like this
List<Cookie> cookies = httpclient.getCookieStore().getCookies();
if (cookies.isEmpty()) {
Log.d(TAG,"no cookies received");
} else {
for (int i = 0; i < cookies.size(); i++) {
if(cookies.get(i).getName().contentEquals("PHPSESSID")) {
PHPSESSID = cookies.get(i).getValue();
}
}
}
To send them back:
nameValuePairs.add(new BasicNameValuePair("PHPSESSID",phpsessid));
httppost.setEntity(new UrlEncodedFormEntity(aList));
aList is all your nameValuePairs
LoopJ has a built in persistent cookie store that can be used with or without the loopj framework
https://github.com/loopj/android-async-http/blob/master/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java
I wrote a simple class named CookieHelper and I've provided an example of how to use this class to help all users that facing the same problem :
https://github.com/augustopicciani/HttpClient-save-cookies-to-file