Question Android - Configuration de Retrofit / Apache HttpClient pour Digest Auth


Je travaille sur un projet Android et j'essaie d'obtenir l'authentification Digest pour travailler avec Retrofit. Je suis un peu étonné que Retrofit ne le supporte pas nativement (ou plus exactement, que OkHttp ne le supporte pas), mais je suppose que cela ne sert à rien.

J'ai parcouru pas mal de discussions ici et il semble que la bonne solution consiste à intégrer Apache HttpClient (qui supporte nativement Digest Auth) avec Retrofit. Cela nécessite le HttpClient encapsulé avec une implémentation retrofit.client.Client. Les valeurs entrantes doivent être analysées et intégrées dans une nouvelle réponse HttpClient qui est ensuite renvoyée à Retrofit pour être traitée normalement. Crédit à Jason Tu et son exemple à: https://gist.github.com/nucleartide/24628083decb65a4562c

Le problème est que ça ne marche pas. Je reçois un 401 Unauthorized à chaque fois et je ne comprends pas pourquoi. Voici mon client impliquer:

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();
}

}

Ma configuration de conversion ressemble à ceci:

RestAdapter final final 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();
}

Je suis perplexe pourquoi je reçois toujours 401 de retour du serveur. J'ai parcouru le processus de construction des réponses et cela me semble propre, alors je pense qu'il me manque quelque chose de fondamental. Les informations d'identification sont bonnes et je les ai vérifiées en dehors de l'application. Quelqu'un a-t-il marché cette promenade avant?


11
2018-06-23 14:45


origine


Réponses:


Vous utilisez un numéro de port 443 pour l'authentification.

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

Mais, il semble que votre vrai numéro de port est 8003.

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

Alors, que diriez-vous d'utiliser le numéro de port 8003 pour l'authentification comme ci-dessous?

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

1
2017-07-16 01:09