2010-06-02 106 views
14

基本上我需要做的是執行摘要認證。我嘗試的第一件事是可用的官方示例here。 但是當我嘗試去執行它(有一些小的變化,郵政代替Get方法),我收到了Apache HttpClient摘要認證

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

當這個失敗我嘗試使用:

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

起初我有隻覆蓋「realm」和「nonce」DigestScheme參數。但事實證明,在服務器上運行的PHP腳本需要所有其他參數,但無論是否指定它們,DigestScheme在我調用authenticate()方法時都不會在Authorization RequestPreperty中生成它們。而PHP腳本會返回HTTP響應代碼200,其中包含PHP腳本需要cnonce,nc和qop參數的消息。

我一直在爲此掙扎兩天,沒有運氣。基於一切,我認爲問題的原因是PHP腳本。在我看來,當應用程序嘗試訪問未經授權的應用程序時,它不會發出挑戰。

任何想法的人?

編輯: 還有一件事,我試着用cURL連接,它的工作原理。

+0

看起來像服務器發送非標準的挑戰。你可以在瀏覽器中試用並獲取標題跟蹤? – 2010-06-02 03:31:20

+0

我已經做了一個HttpURLConnection服務器並打印出響應頭。下面是一個挑戰,怎麼看起來像: 重點= WWW驗證 值=文摘境界=「REST API」 QOP =「權威性」的隨機數=「4c063992df3dd」不透明=「aba3d4b49c454e1974970e7b5514b001」 – anqe1ki11er 2010-06-02 11:04:06

回答

3

我設法在驗證代碼後使用digestScheme進行摘要登錄。

digestAuth.processChallenge(null); 

強制解釋先前的輸入參數。 null參數是一個頭部,基於發送的頭部(如果有的話)。

現在使用qop/nc,並且digestScheme按要求工作。 在Android

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

如何確定的境界編程?此代碼適用於將連接到許多服務器的許多計算機上運行的庫。所以我不能硬編碼。 – 2016-12-27 11:41:09

-2

運行它你們做起來很複雜。如果你閱讀apache httpclient的文檔,這將是非常容易的。

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

此代碼片段爲我工作。您必須通過查看從主機獲得的401響應頭來提供您可以獲得的領域。

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