I'm connecting to a RESTful API which has a login resource: /login. Using the credentials they gave me it results in a nice 200
.
But trying to access protected resources afterwards gives me a 401
(it does work with the Firefox addon RESTClient, though). After debugging, I found out that some cookies get rejected which I suppose are responsible for not letting me in.
The warning message on them is:
Cookie rejected [somename="somevalue", version:0, domain:xyz.org:443, path:/, expiry:null] Illegal 'domain' attribute "xyz:443". Domain of origin: "xyz"
I'm using the Apache HTTP Client httpcomponents-client-4.5.6
to connect to the site. Is there anything I can do? As far as I can see the only thing which bothers it is the :443. The API is only accessible via https. I didn't find out if I could change my access to the site with httpclient, so it does not see a difference in domain names any more.
I searched a lot and came to many outdated solutions regarding CookieSpecProviders and setting CookieSpecs to "easy" - but all this seemed to completely eliminate all cookies. My debug output of the cookie store was always empty after using these solutions (but the warning messages were gone).
I set up a quick and dirty, isolated example:
package apitest;
import java.io.IOException;
import org.apache.http.HttpHost;
import org.apache.http.client.CookieStore;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
public class ApiTest {
public static void main(String[] args) {
HttpHost target = new HttpHost("stackoverflow.com", 443, "https");
HttpClientContext context = HttpClientContext.create();
CookieStore cookieStore = new BasicCookieStore();
HttpClientBuilder clientBuilder = HttpClientBuilder.create().setDefaultCookieStore(cookieStore);
CloseableHttpClient httpClient = clientBuilder.build();
HttpGet stackGet = new HttpGet("");
CloseableHttpResponse response;
try {
response = httpClient.execute(target, stackGet, context);
printCookies(cookieStore);
} catch (IOException e) {
e.printStackTrace();
}
stackGet = new HttpGet("/tags");
try {
response = httpClient.execute(target, stackGet, context);
printCookies(cookieStore);
} catch (IOException e) {
e.printStackTrace();
}
}
static void printCookies(CookieStore cookieStore) {
for (Cookie c : cookieStore.getCookies()) {
System.out.println(c.getName() + " : " + c.getValue());
}
}
}
There are two consecutive GET requests done, which result in the correct behavior. The 'prov' cookie, which should be some sort of session cookie, stays the same. The same thing done with the aforementioned API gives the error.
I don't know if this was necessary to do, but to solve this, I created a new CookieSpec, as recommended on different sources:
EasySpecProvider.class
import org.apache.http.cookie.CookieSpec;
import org.apache.http.cookie.CookieSpecProvider;
import org.apache.http.protocol.HttpContext;
class EasySpecProvider implements CookieSpecProvider {
@Override
public CookieSpec create(HttpContext context) {
return new EasyCookieSpec();
}
}
EasyCookieSpec.class
import org.apache.http.cookie.Cookie;
import org.apache.http.cookie.CookieOrigin;
import org.apache.http.cookie.MalformedCookieException;
import org.apache.http.impl.cookie.DefaultCookieSpec;
class EasyCookieSpec extends DefaultCookieSpec {
@Override
public void validate(Cookie arg0, CookieOrigin arg1) throws MalformedCookieException {
}
}
I registered it via
Registry<CookieSpecProvider> r = RegistryBuilder.<CookieSpecProvider>create()
.register("easy", new EasySpecProvider()).build();
and
clientBuilder.setDefaultCookieSpecRegistry(r)
.setDefaultRequestConfig(RequestConfig.custom().setCookieSpec("easy").build())
into the client builder. After that, all malformed cookies were accepted, but the session cookie changed with every request. I suppose the same thing then happened on the API's server (mismatching domain part of the cookie). I now clear the cookie store on every request and manually recreate the session cookie with a correct domain attribute and now it works.