I have a problem when used HttpURLConnection in Java, The connection to rest server give client cookie after authenticated. I can save the cookies from response header (Set-Cookie) after requesting and use them for next request but cookies that has !httponly flag is not available in response header (Set-Cookie).
I need the session_id cookie with !httponly flaged to be sent to next request so the connection no need to be authenticated in next request after the app exiting.
How can I save all cookies (basic cookies, secure cookies, httponly cookies) in Java just like cURL does?
After searching for a long time, I found the solution: http://jaunt-api.com/
I realize this question is old, but it was the first answer that came up in an internet search.
To resolve, use CookieHandler.setDefault( new CookieManager( null, CookiePolicy.ACCEPT_ALL ) ); per here: Should HttpURLConnection with CookieManager automatically handle session cookies?
Related
I noticed our code is adding the access token / authorization token to the response in the form of a cookie, using
((HttpServletResponse) response).addCookie(accessTokenCookie);
I've done some research and discovered this info:
Request cookies are the cookies sent from browser to server
Response cookies are the cookies sent out (from server to browser).
If this is the case, wouldn't my request interceptor / doFilterInternal need to apply the access token cookie to the request before it goes through, and not the response?
What makes it more confusing is the access token cookie is being created by fetching the access token value using request.getAttribute. If the request already has the access token as an attribute, why does a cookie needed to be added to the response?
You misunderstand how cookies work.
The browser sends a request to some resource on some server.
The server returns the bytes that comprise the resource.
That's the basic flow. Now, let's talk about cookies:
When the server returns those bytes, it can send headers along with it. It is in fact required; for example, to talk about what the data is representing. For example, if you ask for /img/background.png, the server returns the image data and also sends Content-Type: image/png. Because browsers don't actually do the whole 'extensions indicate what the data is' thing, that's what that Content-Type header is for.
One of those headers is a Set-Cookie header.
Set-Cookie headers tell the browser: Take this data and save it somewhere. Next time you load this resource, send it again. There's some control about when to send it (you can make a Set-Cookie header sent when the server reponds for request /foo/bar make the browser send that cookie back even when asking for /foo/baz, or e.g. when foo.myserver.com sends a cookie, it can tell the browser: Send that back also when requesting resources from bar.myserver.com. There are limits though; when setting a cookie when responding to a request on myserver.com, you can't tell the browser to send that back when sending to google.com. Browsers are complex beasts; they ship with a huge list of top-level-ish domains and won't let you do this.
You don't 'add' cookies to a 'request' - the request stuff (the data you can obtain from an HttpServletRequest object) is just representing what the browser sent the server. The model for HttpServletRequest/Response is strictly two phases: The browser sends a request, and the server responds. That's it. It's not a long conversation. Just one message each way, that is all you get.
So, you add a cookie to the 'response' which means that future requests made by that same browser will then send it in the 'request'.
I am using spring security with angular 6. When i login using basic Auth server sends a cookie JessionID with response. I want to send this cookie with other request for authentication purpose but it gives me error Refused to set unsafe header 'Cookie' . When i hit the same endpoint from postman with same cookie in header it works.
Below is the method in angular:
Note: Currently i am manually adding it with headers.
private heroesUrl = 'http://localhost:8080/hi';
header = new HttpHeaders().set("Cookie", "JSESSIONID=A2A75EC9A3E1172D60060C6E708549B5");
getMessage() :Observable<Message>{
return this.http.get<Message>(this.heroesUrl,{headers:this.header});
}
Response which i get when i login using basic Auth
You can't do this, cause the browser doesn't allow you to do it. Let me describe the problem here:
Did you notice the Set-Cookie: JSESSIONID=......; Path=/; HttpOnly in your response headers? Well, The problem is the HttpOnly flag. Actually :) it's not a problem, it's a feature to prevent attacks that aim to steal your browser cookies:
HttpOnly is a flag added to cookies that tell the browser not to display the cookie through client-side scripts (document.cookie and others). ... When you set a cookie with the HttpOnly flag, it informs the browser that this special cookie should only be accessed by the server
So the browser doesn't allow any javascript code to access this variable. If you could change that value, then it's not a HttpOnly flagged cookie anymore:)
If you want to send this cookie via javascript, you should send it via the Authorization header for example and write middleware in Java server so that it captures these values from the Authorization header and think of them as JSESSIONID cookie. No more options for you :)
I also had this issue, and i just fixed it right now.
I realized that is you pass option {withCredentials: true} your browser will automatically send all available cookies along with your request. That way you don't have to add the cookies manually, so it's fluent and i thinks it also safer.
Change your code to this and see and check.
Cookies are available when the path is same as your front end.
private heroesUrl = 'http://localhost:8080/hi';
getMessage() :Observable<Message>{
return this.http.get<Message>(this.heroesUrl, {withCredentials: true});
}
Even for me it seems quite odd to raise this question, as it contradicts my initial understanding.
Problem
Tomcat creates jsessionid on the first request (request1) and sends response (response1-with JSessionID) to the client. And client sends the same via cookies to the server on the next request (request2-with JSessionID). Now server understands that this is on the same session and responds, but the response doesn't contain JSessionID(response2-without JSessionID).
So now the client doesn't get any JSessionID, so the next request from that client seems to be a new one for the server, so server creates another session, which is wrong.
Relative Posts
http://lazyjavadev.blogspot.ie/2013/04/servlet-session-tracking-with-cookies.html
Why isn't getSession() returning the same session in subsequent requests distanced in short time periods? Under what conditions is a JSESSIONID created?
http://grokbase.com/t/tomcat/users/084pdye7fz/tomcat-not-sending-jsessionid-servlet-session-cookie-with-new-sessions
Attempted Solutions
Solution1
Add all cookies from the request to response - IT WORKS, but i think this is tomcat's job.
// Add cookies from request
Cookie[] cookies = req.getCookies();
if(cookies != null){
for (int i = 0; i < cookies.length; i++) {
resp.addCookie(cookies[i]);
}
}
Solution2
Add JSessionID cookie from client from the time of session initiation till session destruction (no matter whether server sends the session id in the response or not) - But this is a workaround and can't be the solution because clients are out of control in real time situation.
Question - ?
It's clear that tomcat maintain's session based on JSessionID via cookies or URL Rewriting or Hidden form fields. I have no special case like disableing cookies. Now the questions are
Why my tomcat doesn't send JSessionID on the subsequent response?
If that's a normal behaviour how tomcat maintains session integrity?
Or is it client's responsibility to send JSessionId cookiee to server untill the cookiee expires?
Thanks for your time in helping me.. :)
I need to get the HttpOnly cookies set as Session cookie in my java code.
To get non HttpOnly cookies I used Jsoup but now am stucked with HttpOnly cookies ?
Note :
Don't know if it matters but the site from which I want to get HttpCookies is developed in ASP.net.
I would expect Jsoup to make those available:
Connection connection = Jsoup.connect("http://example.com");
Connection.Response response = connection.execute();
...then use the cookies map on response.
If the HttpOnly cookies aren't there, you may have to read the contents of the URL directly (e.g., via URLConnection or similar) before passing them on to JSoup.parse, and look for the cookie headers in that stream.
Side note: To get a Document after connecting as with the above, without repeating the request, use Connection#parse:
Document doc = connection.parse();
I just mention this because you're likely to want the document as well as the cookies.
I'm trying to invalidate/expire an insecure cookie from a securely accessed servlet and send a redirect back to the client. However, when the redirect is followed, the request still contains the original, unexpired, uninvalidated (is that a word) cookie.
Here's a more detailed description of the flow:
1) Client requests a particular insecure url backed by Servlet A.
2) Servlet A detects that there is a Cookie XX and redirects to a secure url backed by Servlet B
3) Servlet B does its magic, then invalidates Cookie XX by setting the MaxAge to 0 and redirects to Servlet A via an insecure url.
4) In Servlet A, I'm still able to access the cookie just as it was in the first request.
Can anyone lend a hand? I was under the impression and can't find evidence to the contrary that when a cookie is sent back with a redirect response, it is still processed before the new request is sent out. This is happening in all browsers (Chrome, FF, IE) that I have access to, so I don't think its a browser thing. In HTTPFox and the Chrome Developer tools I can see the original cookie getting sent in the first and second request, the invalidated cookie coming back in the response to the second request, and the original cookie being sent again in the third request. I've tried setting the MaxAge to 0, setting the value of the cookie to null/empty string, and another value but it never changes. All of the server side code is done in Java if it matters.
Help is very much appreciated.
Have you tried making sure that the domain and paths for the invalidated cookie is the same as the original cookie?
Also, a better way to handle sensitive cookies is setting the 'secure' flag on the original cookie. That will tell the browser to never send the cookie over an insecure connection.
This turned out to be an oversight on my part. When Servlet B invalidated Cookie XX, it also set the cookie's path to something other than what it originally was. That, in effect, created a Cookie XX-B and had no effect on the original Cookie XX. Making sure my cookie's paths were the same fixed it.
In two separate projects I've had to invalidate a cookie. This is what I have had to do:
Get the cookie in question from the HTTP request object
Set cookie max age to by invoking Cookie.setMaxAge(int).
Call the Cookie.setPath(String) method, even if path is to remain the same
Add the cookie back into the HTTP response object, I.e. HttpServletRespons.addCookie(cookie)
Only after executing all the steps above did the browser stop passing the cookie back to server on subsequent requests.