quux00
quux00

Reputation: 14634

Cookie management using the Java Apache HttpClient Fluent API

I am having trouble figuring out how to use the Apache HttpComponents/HttpClient Fluent API and get it to properly send back cookies to a web server that requires a login and then sending back the cookies to access other parts of the site. I am using version 4.5.3.

According to the Fluent API tutorial, you can use an (HttpComponents) Executor "in order to execute requests in a specific security context whereby authentication details are cached and re-used for subsequent requests." https://hc.apache.org/httpcomponents-client-4.5.x/tutorial/html/fluent.html

So I tried that but I get a 403 Access Denied on any attempt to access another page after logging in. Here's the code I've tried:

CookieStore httpCookieStore = new BasicCookieStore();
List<Cookie> cookies = httpCookieStore.getCookies();

String username = "admin";
String password = "admin";
Executor httpExecutor = Executor.newInstance().auth(username, password);
httpExecutor.use(httpCookieStore);
Response response = httpExecutor.execute(Request.Get("http://myserver.example.com/login").useExpectContinue());
String loginOutput = response.returnContent().asString();
System.out.println(loginOutput);  // works - gets the expected page

String swaggerUrl = "http://myserver.example.com/swagger/index.html";
response = httpExecutor.execute(Request.Get(swaggerUrl));
HttpResponse httpResponse = response.returnResponse();
System.out.println(httpResponse);  // Response is 403 Access Denied
// prints: HttpResponseProxy{HTTP/1.1 403 Access Denied [X-Content-Type-Options: nosniff, X-XSS-Protection: 1; mode=block, Pragma: no-cache, X-Frame-Options: DENY, Content-Type: text/html;charset=ISO-8859-1, Cache-Control: must-revalidate,no-cache,no-store, Content-Length: 1391, Server: Jetty(8.1.16.v20140903)] [Content-Type: text/html; charset=ISO-8859-1,Content-Length: 1391,Chunked: false]}

I checked the contents of the CookieStore after the login and it has the correct cookie:

System.out.println(httpCookieStore.getCookies().size()); // prints 1
System.out.println(httpCookieStore.getCookies().get(0)); 
// prints: [version: 0][name: JSESSIONID][value: 14b1yp7hf85es1vc6zpe2y376n][domain: myserver.example.com][path: /][expiry: null]

So I also tried explicitly adding the cookie to the Header of the GET Request, but that still fails with same 403 Access Denied error:

CookieStore httpCookieStore = new BasicCookieStore();
List<Cookie> cookies = httpCookieStore.getCookies();

String username = "admin";
String password = "admin";
Executor httpExecutor = Executor.newInstance().auth(username, password);
httpExecutor.use(httpCookieStore);
Response response = httpExecutor.execute(Request.Get("http://myserver.example.com/login").useExpectContinue());
String loginOutput = response.returnContent().asString();
System.out.println(loginOutput);  // works - gets the expected page

String swaggerUrl = "http://myserver.example.com/swagger/index.html";
response = httpExecutor.execute(Request.Get(swaggerUrl).addHeader(authCookieName, authCookieValue));
HttpResponse httpResponse = response.returnResponse();
System.out.println(httpResponse);  // Response is 403 Access Denied

Any ideas how to make this work with the fluent API?

Upvotes: 3

Views: 4022

Answers (1)

Thierry
Thierry

Reputation: 5440

When looking at the HttpClient documentation, you linked, they started with this warning (emphasis mine) :

As of version of 4.2 HttpClient comes with an easy to use facade API based on the concept of a fluent interface. Fluent facade API exposes only the most fundamental functions of HttpClient and is intended for simple use cases that do not require the full flexibility of HttpClient. For instance, fluent facade API relieves the users from having to deal with connection management and resource deallocation.

You might well be in the case of unsupported configuration through the fluent api (and to answer your quote from their doc, authentication, and session management are linked, but not mandatory with each other : you might have some stateless service that ask for auth info with every request without ever starting a session, and you can obviously create session (backed by a cookie) without ever asking auth info)

You might have to resort to the other, more verbose, API :

BasicCookieStore cookieStore = new BasicCookieStore();
CloseableHttpClient httpclient = HttpClients.custom()
    .setDefaultCookieStore(cookieStore)
    .build();
try {
    HttpGet httpget = new HttpGet("https://someportal/");
    CloseableHttpResponse response1 = httpclient.execute(httpget);
    try {
       ...

Upvotes: 5

Related Questions