2010-06-02 15 views
14

Grundsätzlich, was ich tun muss, ist Digest-Authentifizierung durchzuführen. Das erste, was ich versuchte, ist das offizielle Beispiel zur Verfügung here. Aber wenn ich versuche, es auszuführen (mit einigen kleinen Änderungen, Post anstelle der die Get-Methode) Ich erhalte eineApache HttpClient Digest Authentifizierung

org.apache.http.auth.MalformedChallengeException: missing nonce in challange 
at org.apache.http.impl.auth.DigestScheme.processChallenge(DigestScheme.java:132) 

Als dies fehlschlug ich versucht, mit:

DefaultHttpClient client = new DefaultHttpClient(); 
client.getCredentialsProvider().setCredentials(new AuthScope(null, -1, null), new UsernamePasswordCredentials("<username>", "<password>")); 

HttpPost post = new HttpPost(URI.create("http://<someaddress>")); 
     List<NameValuePair> nvps = new ArrayList<NameValuePair>(); 
nvps.add(new BasicNameValuePair("domain", "<username>")); 
post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8)); 

DigestScheme digestAuth = new DigestScheme(); 
digestAuth.overrideParamter("algorithm", "MD5"); 
digestAuth.overrideParamter("realm", "http://<someaddress>"); 
digestAuth.overrideParamter("nonce", Long.toString(new Random().nextLong(), 36)); 
digestAuth.overrideParamter("qop", "auth"); 
digestAuth.overrideParamter("nc", "0"); 
digestAuth.overrideParamter("cnonce", DigestScheme.createCnonce()); 

Header auth = digestAuth.authenticate(new 
     UsernamePasswordCredentials("<username>", "<password>"), post); 
System.out.println(auth.getName()); 
System.out.println(auth.getValue()); 
post.setHeader(auth); 


HttpResponse ret = client.execute(post); 
ByteArrayOutputStream v2 = new ByteArrayOutputStream(); 
ret.getEntity().writeTo(v2); 
System.out.println("----------------------------------------"); 
System.out.println(v2.toString()); 
System.out.println("----------------------------------------"); 
System.out.println(ret.getStatusLine().getReasonPhrase()); 
System.out.println(ret.getStatusLine().getStatusCode()); 

Zuerst habe ich überschreibt nur die DigestScheme-Parameter "realm" und "nonce". Aber es stellte sich heraus, dass das PHP-Skript, das auf dem Server läuft, alle anderen Parameter benötigt, aber egal, ob ich sie spezifiziere oder nicht, DigestScheme generiert sie nicht in der Autorisierungs-RequestPreperty, wenn ich seine authenticate() -Methode aufruft. Und das PHP-Skript gibt den HTTP-Antwortcode 200 mit einer Meldung zurück, dass das PHP-Skript die Parameter cnonce, nc und qop benötigt.

Ich habe seit zwei Tagen damit zu kämpfen, und kein Glück. Basierend auf allem, was ich denke, ist das PHP-Skript die Ursache des Problems. Es scheint mir, dass es keine Herausforderung sendet, wenn die App versucht, unautorisiert darauf zuzugreifen.

Irgendwelche Ideen jemand?

Bearbeiten: Noch eine Sache, ich habe versucht, mit cURL verbinden und es funktioniert.

+0

Sieht aus wie der Server nicht standardmäßige Herausforderungen sendet. Kannst du es im Browser versuchen und einen Header-Trace bekommen? –

+0

Ich habe eine HttpURLConnection zum Server gemacht und die Antwortheader ausgedruckt. Im Folgenden sehen Sie, wie eine Herausforderung aussieht: Key = www-authenticate Wert = Digest Realm = "REST-API" qop = "auth" nonce = "4c063992df3dd" opak = "aba3d4b49c454e1974970e7b5514b001" – anqe1ki11er

Antwort

3

Ich habe es geschafft, eine Digest Anmeldung mit digestScheme nach Überprüfung des Codes zu tun.

digestAuth.processChallenge(null); 

Erzwingt die Interpretation der vorherigen Eingabeparameter. Der Null-Parameter ist ein Header, basierend auf dem gesendeten Header, falls vorhanden.

Jetzt wird qop/nc verwendet und digestScheme funktioniert wie erforderlich. es auf Android

Lauf
digestAuth.overrideParamter("algorithm", "MD5"); 
digestAuth.overrideParamter("realm", serverRealm); 
digestAuth.overrideParamter("nonce", Long.toString(new Random().nextLong(), 36)); 
digestAuth.overrideParamter("qop", "auth");// not effective 
digestAuth.overrideParamter("nc",""+sequence);//nt effective 
digestAuth.overrideParamter("cnonce", DigestScheme.createCnonce()); 
digestAuth.overrideParamter("opaque","ba897c2f0f3de9c6f52d"); 
String err; 
try 
{ 
    digestAuth.processChallenge(null); 
    //force qop in use chalange on return header ????!!!! 
} 
catch (Exception e) 
{ 
    err=e.getLocalizedMessage(); 
} 
+0

Wie kann ich den Realm programmatisch ermitteln? Dieser Code gilt für eine Bibliothek, die auf vielen Computern mit vielen Servern ausgeführt wird. Also kann ich es nicht hart codieren. –

-2

Ihr Jungs machen es so kompliziert. Wenn Sie die Dokumentation von Apache httpclient lesen, wäre es super einfach.

protected static void downloadDigest(URL url, FileOutputStream fos) 
    throws IOException { 
    HttpHost targetHost = new HttpHost(url.getHost(), url.getPort(), url.getProtocol()); 
    CloseableHttpClient httpClient = HttpClients.createDefault(); 
    HttpClientContext context = HttpClientContext.create(); 

    String credential = url.getUserInfo(); 
    if (credential != null) { 
     String user = credential.split(":")[0]; 
     String password = credential.split(":")[1]; 

     CredentialsProvider credsProvider = new BasicCredentialsProvider(); 
     credsProvider.setCredentials(AuthScope.ANY, 
      new UsernamePasswordCredentials(user, password)); 
     AuthCache authCache = new BasicAuthCache(); 
     DigestScheme digestScheme = new DigestScheme(); 
     authCache.put(targetHost, digestScheme); 

     context.setCredentialsProvider(credsProvider); 
     context.setAuthCache(authCache); 
    } 

    HttpGet httpget = new HttpGet(url.getPath()); 

    CloseableHttpResponse response = httpClient.execute(targetHost, httpget, context); 

    try { 
     ReadableByteChannel rbc = Channels.newChannel(response.getEntity().getContent()); 
     fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 
    } finally { 
     response.close(); 
    } 
} 
1

Dieser Codeausschnitt funktionierte für mich. Sie müssen den Realm angeben, den Sie erhalten, indem Sie sich den 401-Response-Header anschauen, den Sie vom Host erhalten.

val credsProvider = new BasicCredentialsProvider(); 
credsProvider.setCredentials(AuthScope.ANY, 
    new UsernamePasswordCredentials(user, password)); 
val authCache = new BasicAuthCache(); 
val digestScheme = new DigestScheme(); 

digestScheme.overrideParamter("realm", "**Name of the Realm**"); 
// Nonce value 
digestScheme.overrideParamter("nonce", "whatever"); 

authCache.put(targetHost, digestScheme); 

context.setCredentialsProvider(credsProvider); 
context.setAuthCache(authCache); 

val httpget = new HttpGet(url); 

val response = httpClient.execute(targetHost, httpget, context); 
Verwandte Themen