2010-06-02 95 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);