001/* 002 * Licensed to DuraSpace under one or more contributor license agreements. 003 * See the NOTICE file distributed with this work for additional information 004 * regarding copyright ownership. 005 * 006 * DuraSpace licenses this file to you under the Apache License, 007 * Version 2.0 (the "License"); you may not use this file except in 008 * compliance with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.fcrepo.client; 019 020import static org.apache.commons.lang3.StringUtils.isBlank; 021import static org.slf4j.LoggerFactory.getLogger; 022 023import java.io.IOException; 024 025import org.apache.http.HttpException; 026import org.apache.http.HttpHost; 027import org.apache.http.HttpRequest; 028import org.apache.http.HttpRequestInterceptor; 029import org.apache.http.auth.AuthScope; 030import org.apache.http.auth.AuthState; 031import org.apache.http.auth.Credentials; 032import org.apache.http.auth.UsernamePasswordCredentials; 033import org.apache.http.client.CredentialsProvider; 034import org.apache.http.client.protocol.HttpClientContext; 035import org.apache.http.impl.auth.BasicScheme; 036import org.apache.http.impl.client.BasicCredentialsProvider; 037import org.apache.http.impl.client.CloseableHttpClient; 038import org.apache.http.impl.client.HttpClients; 039import org.apache.http.protocol.HttpContext; 040import org.apache.http.protocol.HttpCoreContext; 041import org.slf4j.Logger; 042 043/** 044 * A utility class for building an httpclient for interacting with a Fedora repository 045 * 046 * @author Aaron Coburn 047 * @since March 9, 2015 048 */ 049public class FcrepoHttpClientBuilder { 050 051 private String username; 052 053 private String password; 054 055 private String host; 056 057 private static final Logger LOGGER = getLogger(FcrepoHttpClientBuilder.class); 058 059 /** 060 * Create a FcrepoHttpClientBuilder object with which it is possible to create 061 * an HttpClient object 062 * 063 * @param username an optional username for authentication 064 * @param password an optional password for authentication 065 * @param host an optional realm for authentication 066 */ 067 public FcrepoHttpClientBuilder(final String username, final String password, final String host) { 068 this.username = username; 069 this.password = password; 070 this.host = host; 071 } 072 073 /** 074 * Build an HttpClient 075 * 076 * @return an HttpClient 077 */ 078 public CloseableHttpClient build() { 079 080 if (isBlank(username) || isBlank(password)) { 081 return HttpClients.createSystem(); 082 } else { 083 LOGGER.debug("Accessing fcrepo with user credentials"); 084 085 final CredentialsProvider credsProvider = new BasicCredentialsProvider(); 086 AuthScope scope = null; 087 088 if (isBlank(host)) { 089 scope = new AuthScope(AuthScope.ANY); 090 } else { 091 scope = new AuthScope(new HttpHost(host)); 092 } 093 credsProvider.setCredentials( 094 scope, 095 new UsernamePasswordCredentials(username, password)); 096 return HttpClients.custom() 097 .setDefaultCredentialsProvider(credsProvider) 098 .useSystemProperties() 099 .addInterceptorFirst(new PreemptiveAuthInterceptor()) 100 .build(); 101 } 102 } 103 104 static class PreemptiveAuthInterceptor implements HttpRequestInterceptor { 105 106 public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { 107 final AuthState authState = (AuthState) context.getAttribute(HttpClientContext.TARGET_AUTH_STATE); 108 // If no auth scheme available yet, try to initialize it 109 // preemptively 110 if (authState.getAuthScheme() == null) { 111 final CredentialsProvider credsProvider = (CredentialsProvider) 112 context.getAttribute(HttpClientContext.CREDS_PROVIDER); 113 final HttpHost targetHost = (HttpHost) context.getAttribute(HttpCoreContext.HTTP_TARGET_HOST); 114 final AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort()); 115 final Credentials creds = credsProvider.getCredentials(authScope); 116 if (creds == null) { 117 LOGGER.debug("Cannot initiate preemtive authentication, Credentials not found!"); 118 } 119 authState.update(new BasicScheme(), creds); 120 } 121 } 122 } 123}