android - vulnerability - http pinning
Android-ConfiguraciĆ³n de Retrofit/Apache HttpClient para Digest Auth (1)
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);
Estoy trabajando en un proyecto de Android e intento que Autenticación implícita funcione con Retrofit. Estoy algo sorprendido de que Retrofit no lo soporte de forma nativa (o más exactamente, que OkHttp no lo respalde), pero no me refiero a ningún punto, supongo.
Crucé varios hilos aquí y parece que la solución correcta es integrar Apache HttpClient (que de forma nativa admite Digest Auth) con Retrofit. Esto requiere que HttpClient se complete con una implementación retrofit.client.Client. Los valores entrantes de reequipamiento deben analizarse y compilarse en una nueva respuesta de HttpClient que luego se envía 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. Recibo un 401 no autorizado cada vez y no tengo claro 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 actualización se ve así:
final público 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 perplejo por qué constantemente estoy recibiendo 401 del servidor. He recorrido el proceso de creación de respuestas y me parece limpio, así que estoy pensando que me estoy perdiendo algo fundamental. Las credenciales son buenas y las he verificado fuera de la aplicación. ¿Alguien caminó esta caminata antes?