2

I tried doing PreEmptive Authentication for a Basic Auth protected Solr using this class https://subversion.jfrog.org/jfrog/build-info/trunk/build-info-client/src/main/java/org/jfrog/build/client/PreemptiveHttpClient.java and Solr , but the methods were Deprecated so I do not know if this was a problem. The situation is in querying is fine in Solr but for indexing I am getting a IOException occured when talking to server at: example.com:8983/solr/core1 .

The HttpSolrClient constructor requires an httpClient as a parameter to do preemptive authorization so with the class above since the httpClient is stored in a private variable I used a getter on that variable to get the httpClient and pass to the HttpSolrClient constructor. Not sure if I did that right either.

PreemptiveAuthenticate preemp = new PreemptiveAuthenticate("username", "password", 1);
    DefaultHttpClient httpClient = preemp.getHttpClient();
    System.out.println("Made it to connectSolr after set Authentication");
    SolrClient solr = new HttpSolrClient(urlString, httpClient);

I am aware of examples like http://hc.apache.org/httpcomponents-client-ga/tutorial/html/authentication.html Example 4.6 to do preemptive authorization with HttpClient 4.3 , but this is a test case and I do not see a way to pass the HttpClient so that I can do preemptive authentication.

Andrae Browne
  • 87
  • 1
  • 9

2 Answers2

4

Fixing Paulius's code, preemptive authentication for HttpClient 4.3. Create methods in a class the call createHttpClient when need to connect to Solr.

public static HttpClient createHttpClient(String username, String password) {
    if (username == null) {
        username = "";
    }
    if (password == null) {
        password = "";
    }
    HttpClientBuilder clientBuilder = HttpClientBuilder.create();

    BasicCredentialsProvider provider = new BasicCredentialsProvider();
    provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));

    clientBuilder.setDefaultCredentialsProvider(provider);
    clientBuilder.addInterceptorFirst(new PreemptiveAuthInterceptor());
    return clientBuilder.build();
}

static class PreemptiveAuthInterceptor implements HttpRequestInterceptor {
    @Override
    public void process (HttpRequest request, HttpContext context) throws HttpException {
        AuthState authState = (AuthState) context.getAttribute(HttpClientContext.TARGET_AUTH_STATE);
        if (authState.getAuthScheme() == null) {
            CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(HttpClientContext.CREDS_PROVIDER);
            HttpHost targetHost = (HttpHost) context.getAttribute(HttpCoreContext.HTTP_TARGET_HOST);
            Credentials credentials = credsProvider.getCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()));
            if (credentials == null) {
                throw new HttpException("No credentials provided for preemptive authentication.");
            }
            authState.update(new BasicScheme(), credentials);
        }
    }
}
cheffe
  • 9,345
  • 2
  • 46
  • 57
Andrae Browne
  • 87
  • 1
  • 9
  • amazing! works with solrj 6.5.0 and CloudSolrClient as well! ex: CloudSolrClient.Builder scb = new CloudSolrClient.Builder(); scb.withHttpClient("YOUR CUSTOM HTTPCLIENT"); CloudSolrClient solr_client = scb.withZkHost("ZK_ADDRESS").build(); – dsncode May 05 '17 at 10:45
  • This is better than the documentation. The only 2 solutions the docs offer are set it for every request, and you can't use typical helper methods like query() or update(). Or set convoluted system properties which aren't always convenient. Why don't we have a straightforward API (setBasicAuth(x,y)) on SolrClient/Builder? This feels like this should be a one line, use autocomplete to find it, done. Not reading scads of docs and stackoverflow posts to figure random things out. – chubbsondubs Jun 11 '21 at 19:23
0

You have to create HttpClient like this:

public static HttpClient createHttpClient(String username, String password) {
    if (username == null) {
        username = "";
    }
    if (password == null) {
        password = "";
    }
    HttpClientBuilder clientBuilder = HttpClientBuilder.create();

    BasicCredentialsProvider provider = new BasicCredentialsProvider();
    provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));

    clientBuilder.setDefaultCredentialsProvider(provider);
    clientBuilder.addInterceptorFirst((HttpRequest request, HttpContext context) -> {
        AuthState authState = (AuthState) context.getAttribute(HttpClientContext.TARGET_AUTH_STATE);
        if (authState.getAuthScheme() == null) {
            CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(HttpClientContext.CREDS_PROVIDER);
            HttpHost targetHost = (HttpHost) context.getAttribute(HttpCoreContext.HTTP_TARGET_HOST);
            Credentials credentials = credsProvider.getCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()));
            if (credentials == null) {
                throw new HttpException("No credentials provided for preemptive authentication.");
            }
            authState.update(new BasicScheme(), credentials);
        }
    });
    return clientBuilder.build();
}

Then you have to give it to the solr server and your requests will be authenticated preemptively.

Paulius Matulionis
  • 23,085
  • 22
  • 103
  • 143
  • this looks like the best code for updated versions , but I am getting errors testing for the addInterceptorFirst parameter seem wrong, it saying it accepts an HttpRequestInterceptor – Andrae Browne Jul 19 '15 at 18:59