001/* 002 * The contents of this file are subject to the license and copyright 003 * detailed in the LICENSE and NOTICE files at the root of the source 004 * tree. 005 */ 006package org.fcrepo.client; 007 008import static org.apache.commons.lang3.StringUtils.isBlank; 009import static org.slf4j.LoggerFactory.getLogger; 010 011import java.io.IOException; 012 013import org.apache.http.HttpException; 014import org.apache.http.HttpHost; 015import org.apache.http.HttpRequest; 016import org.apache.http.HttpRequestInterceptor; 017import org.apache.http.auth.AuthScope; 018import org.apache.http.auth.AuthState; 019import org.apache.http.auth.Credentials; 020import org.apache.http.auth.UsernamePasswordCredentials; 021import org.apache.http.client.CredentialsProvider; 022import org.apache.http.client.protocol.HttpClientContext; 023import org.apache.http.impl.auth.BasicScheme; 024import org.apache.http.impl.client.BasicCredentialsProvider; 025import org.apache.http.impl.client.CloseableHttpClient; 026import org.apache.http.impl.client.HttpClients; 027import org.apache.http.protocol.HttpContext; 028import org.apache.http.protocol.HttpCoreContext; 029import org.slf4j.Logger; 030 031/** 032 * A utility class for building an httpclient for interacting with a Fedora repository 033 * 034 * @author Aaron Coburn 035 * @since March 9, 2015 036 */ 037public class FcrepoHttpClientBuilder { 038 039 private String username; 040 041 private String password; 042 043 private String host; 044 045 private static final Logger LOGGER = getLogger(FcrepoHttpClientBuilder.class); 046 047 /** 048 * Create a FcrepoHttpClientBuilder object with which it is possible to create 049 * an HttpClient object 050 * 051 * @param username an optional username for authentication 052 * @param password an optional password for authentication 053 * @param host an optional realm for authentication 054 */ 055 public FcrepoHttpClientBuilder(final String username, final String password, final String host) { 056 this.username = username; 057 this.password = password; 058 this.host = host; 059 } 060 061 /** 062 * Build an HttpClient 063 * 064 * @return an HttpClient 065 */ 066 public CloseableHttpClient build() { 067 068 if (isBlank(username) || isBlank(password)) { 069 return HttpClients.createSystem(); 070 } else { 071 LOGGER.debug("Accessing fcrepo with user credentials"); 072 073 final CredentialsProvider credsProvider = new BasicCredentialsProvider(); 074 AuthScope scope = null; 075 076 if (isBlank(host)) { 077 scope = new AuthScope(AuthScope.ANY); 078 } else { 079 scope = new AuthScope(new HttpHost(host)); 080 } 081 credsProvider.setCredentials( 082 scope, 083 new UsernamePasswordCredentials(username, password)); 084 return HttpClients.custom() 085 .setDefaultCredentialsProvider(credsProvider) 086 .useSystemProperties() 087 .addInterceptorFirst(new PreemptiveAuthInterceptor()) 088 .build(); 089 } 090 } 091 092 static class PreemptiveAuthInterceptor implements HttpRequestInterceptor { 093 094 public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { 095 final AuthState authState = (AuthState) context.getAttribute(HttpClientContext.TARGET_AUTH_STATE); 096 // If no auth scheme available yet, try to initialize it 097 // preemptively 098 if (authState.getAuthScheme() == null) { 099 final CredentialsProvider credsProvider = (CredentialsProvider) 100 context.getAttribute(HttpClientContext.CREDS_PROVIDER); 101 final HttpHost targetHost = (HttpHost) context.getAttribute(HttpCoreContext.HTTP_TARGET_HOST); 102 final AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort()); 103 final Credentials creds = credsProvider.getCredentials(authScope); 104 if (creds == null) { 105 LOGGER.debug("Cannot initiate preemtive authentication, Credentials not found!"); 106 } 107 authState.update(new BasicScheme(), creds); 108 } 109 } 110 } 111}