Android – Configuración de Retrofit / Apache HttpClient para Digest Auth

Estoy trabajando en un proyecto de Android y tratando de conseguir que Digest Authentication funcione con Retrofit. Estoy un poco sorprendido Retrofit no lo apoya nativamente (o más exactamente, que OkHttp no lo soporta), pero no hay punto de quejarse supongo.

He cruzado a través de unos cuantos hilos aquí y parece que la solución correcta es integrar el Apache HttpClient (que admite nativamente Digest Auth) con Retrofit. Esto requiere envuelto el HttpClient con una implementación retrofit.client.Client. Los valores entrantes de adaptación tienen que ser analizados y construidos en una nueva respuesta HttpClient que luego se envía de nuevo a Retrofit para que se procese normalmente. Crédito a Jason Tu y su ejemplo en: https://gist.github.com/nucleartide/24628083decb65a4562c

El problema es que no está funcionando. Estoy recibiendo un 401 desautorizado cada vez y no está claro para mí por qué. Aquí está mi Cliente impl:

public class AuthClientRedirector implements Client { private final CloseableHttpClient delegate; public AuthClientRedirector(String user, String pass, String hostname, String scope) { Credentials credentials = new UsernamePasswordCredentials(user, pass); AuthScope authScope = new AuthScope(hostname, 443, scope); CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); credentialsProvider.setCredentials(authScope, credentials); delegate = HttpClientBuilder.create() .setDefaultCredentialsProvider(credentialsProvider) .build(); } @Override public Response execute(Request request) { // // We're getting a Retrofit request, but we need to execute an Apache // HttpUriRequest instead. Use the info in the Retrofit request to create // an Apache HttpUriRequest. // String method = request.getMethod(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); if (request.getBody() != null) { try { request.getBody().writeTo(bos); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } String body = new String(bos.toByteArray()); HttpUriRequest wrappedRequest; switch (method) { case "GET": wrappedRequest = new HttpGet(request.getUrl()); break; case "POST": wrappedRequest = new HttpPost(request.getUrl()); wrappedRequest.addHeader("Content-Type", "application/xml"); try { ((HttpPost) wrappedRequest).setEntity(new StringEntity(body)); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } break; case "PUT": wrappedRequest = new HttpPut(request.getUrl()); wrappedRequest.addHeader("Content-Type", "application/xml"); try { ((HttpPut) wrappedRequest).setEntity(new StringEntity(body)); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } break; case "DELETE": wrappedRequest = new HttpDelete(request.getUrl()); break; default: throw new AssertionError("HTTP operation not supported."); } CloseableHttpResponse apacheResponse = null; try { apacheResponse = delegate.execute(wrappedRequest); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(apacheResponse!=null){ // Perform the HTTP request. CloseableHttpResponse response = null; try { response = delegate.execute(wrappedRequest); // Return a Retrofit response. List<Header> retrofitHeaders = toRetrofitHeaders( response.getAllHeaders()); TypedByteArray responseBody; if (response.getEntity() != null) { responseBody = new TypedByteArray("", toByteArray(response.getEntity())); } else { responseBody = new TypedByteArray("", new byte[0]); } System.out.println("this is the response"); System.out.println(new String(responseBody.getBytes())); return new retrofit.client.Response(request.getUrl(), response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase(), retrofitHeaders, responseBody); } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if (response != null) { try { response.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } //failed to return a new retrofit Client return null; } private List<Header> toRetrofitHeaders(org.apache.http.Header[] headers) { List<Header> retrofitHeaders = new ArrayList<>(); for (org.apache.http.Header header : headers) { retrofitHeaders.add(new Header(header.getName(), header.getValue())); } return retrofitHeaders; } private byte[] toByteArray(HttpEntity entity) throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); entity.writeTo(bos); return bos.toByteArray(); } 

}

Mi configuración de reacondicionamiento tiene este aspecto:

Public final RestAdapter configureService () {

 AuthClientRedirector digestAuthMgr = new AuthClientRedirector(username,password,"myhostname","public"); RestAdapter.Builder builder = new RestAdapter.Builder() .setEndpoint("http://myhostname:8003/endpoint") .setLogLevel(RestAdapter.LogLevel.FULL) .setClient(digestAuthMgr); return builder.build(); } 

Estoy stumped por qué estoy constantemente conseguir 401s volver del servidor. He caminado a través del proceso de construcción de la respuesta y se ve limpio para mí, así que estoy pensando que estoy perdiendo algo fundamental. Las credenciales son buenas y las he verificado fuera de la aplicación. ¿Alguien caminó este paseo antes?

Está utilizando el número de puerto 443 para la autenticación.

 AuthScope authScope = new AuthScope(hostname, 443, scope); 

Pero, parece que su número de puerto real es 8003 .

 RestAdapter.Builder builder = new RestAdapter.Builder() .setEndpoint("http://myhostname:8003/endpoint") 

Entonces, ¿qué tal usar el número de puerto 8003 para la autenticación como a continuación?

 AuthScope authScope = new AuthScope(hostname, 8003, scope); 
  • Solo observable con varios suscriptores
  • Por qué Android Circle Progress Dialog Cómo se congela cuando un montón de datos Sincronización de servidor a DB local mediante Retrofit
  • ¡Retrofit! Devolver un tipo genérico observable
  • La fábrica del convertidor de retroadaptación no puede acceder a GsonConverterFactory
  • Cómo llamar al método GET simple usando "Retrofit"
  • Establecer Retrofit RestAdapter.LogLevel a algo que no sea FULL produce un cuerpo de respuesta vacía
  • ¿Cuándo se debe usar RxJava Observable y cuándo Callback simple en Android?
  • Comprensión de flujos de datos y múltiples suscriptores (con retroadaptación)
  • No vuelva a ejecutar la llamada de Retrofit si todavía está en curso con RxJava 2
  • POST con Android Retrofit
  • RxJava dividir uno Observable a dos subObservables
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.