2012-03-27 159 views
5

我正在使用Kerberos身份验证写入HTTP连接。我有“HTTP/1.1 401 Unauthorized”。你能推荐我应该检查什么吗?我认为这有一些技巧,但我没有看到它。使用HTTP客户端的Kerberos连接

可能是我应该设置标题“WWW-Authenticate”与“协商”?

非常感谢先进的任何帮助和想法。

public class ClientKerberosAuthentication { 

    public static void main(String[] args) throws Exception { 

     System.setProperty("java.security.auth.login.config", "login.conf"); 
     System.setProperty("java.security.krb5.conf", "krb5.conf"); 
     System.setProperty("sun.security.krb5.debug", "true"); 
     System.setProperty("javax.security.auth.useSubjectCredsOnly","false"); 

     DefaultHttpClient httpclient = new DefaultHttpClient(); 
     try { 
      NegotiateSchemeFactory nsf = new NegotiateSchemeFactory(); 
      httpclient.getAuthSchemes().register(AuthPolicy.SPNEGO, nsf);    

      List<String> authpref = new ArrayList<String>(); 
      authpref.add(AuthPolicy.BASIC); 
      authpref.add(AuthPolicy.SPNEGO); 
      httpclient.getParams().setParameter(AuthPNames.PROXY_AUTH_PREF, authpref);    


      httpclient.getCredentialsProvider().setCredentials(
        new AuthScope(null, -1, AuthScope.ANY_REALM, AuthPolicy.SPNEGO), 
        new UsernamePasswordCredentials("myuser", "mypass"));    

      System.out.println("----------------------------------------"); 
      HttpUriRequest request = new HttpGet("http://localhost:8084/web-app/webdav/213/_test.docx"); 
      HttpResponse response = httpclient.execute(request); 
      HttpEntity entity = response.getEntity(); 

      System.out.println("----------------------------------------"); 
      System.out.println(response.getStatusLine()); 
      System.out.println("----------------------------------------"); 
      if (entity != null) { 
       System.out.println(EntityUtils.toString(entity)); 
      } 
      System.out.println("----------------------------------------"); 

      // This ensures the connection gets released back to the manager 
      EntityUtils.consume(entity); 

     } finally { 
      httpclient.getConnectionManager().shutdown(); 
     } 
    } 
} 
+0

我已经为此问题写了一个替代解决方案在这里:http://stackoverflow.com/a/22865583/381161 – 2014-04-04 14:53:03

回答

0

我有同样的问题,只是找到您的文章。我将它加入书签,以便我在修复它时发布答案。我发布了一个链接到我的问题,在那里有人回答,所以如果有人通过Google发现这个问题,他们会找到答案:

HttpClient在URL有端口时为AD创建SPN时出现问题。

见我的问题回答+这里:HttpClient check Kerberos secured webpage. NTLM login didn't work

3

SPNEGO不会起作用,因为你用localhost为URL的主机名。

您的服务器配置为在ActiveDirectory服务帐户上注册的以HTTP/开头的一组SPN(或至少一个)。您可以从AD查询它们,感谢setspn -l yourServiceAccount

您的URL必须使用ActiveDirectory中称为SPN的有效服务器主机名,以便Apache Http Client可以协商此服务的TGS并将其发送到您的服务器。

0

这是我在我的项目中编写的测试客户端。 此客户端依赖于所有加密类型要在JDK启用,

如果你看到下面在你的日志和你的密钥表在256位默认的etypes被加密default_tkt_enctypes: 17 16 23 1 3.

则以下jar http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html 需求是下载并放置在JDK/jre/lib/security使AES256位加密后,你应该看到以下日志中默认的etypes为default_tkt_enctypes: 18 17 16 23 1 3.

import java.io.IOException; 
import java.io.InputStream; 
import java.security.Principal; 
import java.security.PrivilegedAction; 
import java.util.Arrays; 
import java.util.HashMap; 
import java.util.HashSet; 
import java.util.Set; 

import javax.security.auth.Subject; 
import javax.security.auth.kerberos.KerberosPrincipal; 
import javax.security.auth.login.AppConfigurationEntry; 
import javax.security.auth.login.Configuration; 
import javax.security.auth.login.LoginContext; 

import org.apache.commons.io.IOUtils; 
import org.apache.http.HttpResponse; 
import org.apache.http.auth.AuthSchemeProvider; 
import org.apache.http.auth.AuthScope; 
import org.apache.http.auth.Credentials; 
import org.apache.http.client.CookieStore; 
import org.apache.http.client.HttpClient; 
import org.apache.http.client.config.AuthSchemes; 
import org.apache.http.client.config.CookieSpecs; 
import org.apache.http.client.config.RequestConfig; 
import org.apache.http.client.methods.HttpGet; 
import org.apache.http.client.methods.HttpUriRequest; 
import org.apache.http.config.Lookup; 
import org.apache.http.config.RegistryBuilder; 
import org.apache.http.impl.auth.SPNegoSchemeFactory; 
import org.apache.http.impl.client.BasicCookieStore; 
import org.apache.http.impl.client.BasicCredentialsProvider; 
import org.apache.http.impl.client.CloseableHttpClient; 
import org.apache.http.impl.client.HttpClientBuilder; 
import org.apache.http.impl.cookie.BasicClientCookie; 

的实用工具类

public class KerberosHttpClient { 
    private String principal; 
    private String keyTabLocation; 

    public KerberosHttpClient() {} 
    public KerberosHttpClient(String principal, String keyTabLocation) { 
     super(); 
     this.principal = principal; 
     this.keyTabLocation = keyTabLocation; 
    } 

    public KerberosHttpClient(String principal, String keyTabLocation, String krb5Location) { 
     this(principal, keyTabLocation); 
     System.setProperty("java.security.krb5.conf", krb5Location); 
    } 

    public KerberosHttpClient(String principal, String keyTabLocation, boolean isDebug) { 
     this(principal, keyTabLocation); 
     if (isDebug) { 
      System.setProperty("sun.security.spnego.debug", "true"); 
      System.setProperty("sun.security.krb5.debug", "true"); 
     } 
    } 

    public KerberosHttpClient(String principal, String keyTabLocation, String krb5Location, boolean isDebug) { 
     this(principal, keyTabLocation, isDebug);   
     System.setProperty("java.security.krb5.conf", krb5Location); 
    } 

    private static HttpClient buildSpengoHttpClient() { 
     HttpClientBuilder builder = HttpClientBuilder.create();    
     Lookup<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create(). 
       register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory(true)).build(); 
     builder.setDefaultAuthSchemeRegistry(authSchemeRegistry); 
     BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider(); 
     credentialsProvider.setCredentials(new AuthScope(null, -1, null), new Credentials() { 
      @Override 
      public Principal getUserPrincipal() { 
       return null; 
      } 
      @Override 
      public String getPassword() { 
       return null; 
      } 
     }); 
     builder.setDefaultCredentialsProvider(credentialsProvider);   
     CloseableHttpClient httpClient = builder.build(); 
     return httpClient; 
    } 

    public HttpResponse callRestUrl(final String url,final String userId) { 
     //keyTabLocation = keyTabLocation.substring("file://".length()); 
     System.out.println(String.format("Calling KerberosHttpClient %s %s %s",this.principal, this.keyTabLocation, url)); 
     Configuration config = new Configuration() { 
      @SuppressWarnings("serial") 
      @Override 
      public AppConfigurationEntry[] getAppConfigurationEntry(String name) { 
       return new AppConfigurationEntry[] { new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule", 
         AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, new HashMap<String, Object>() { 
          { 
           put("useTicketCache", "false"); 
           put("useKeyTab", "true"); 
           put("keyTab", keyTabLocation); 
           //Krb5 in GSS API needs to be refreshed so it does not throw the error 
           //Specified version of key is not available 
           put("refreshKrb5Config", "true"); 
           put("principal", principal); 
           put("storeKey", "true"); 
           put("doNotPrompt", "true"); 
           put("isInitiator", "true"); 
           put("debug", "true"); 
          } 
         }) }; 
      } 
     }; 
     Set<Principal> princ = new HashSet<Principal>(1); 
     princ.add(new KerberosPrincipal(userId)); 
     Subject sub = new Subject(false, princ, new HashSet<Object>(), new HashSet<Object>()); 
     try { 
      LoginContext lc = new LoginContext("", sub, null, config); 
      lc.login(); 
      Subject serviceSubject = lc.getSubject(); 
      return Subject.doAs(serviceSubject, new PrivilegedAction<HttpResponse>() { 
       HttpResponse httpResponse = null; 
       @Override 
       public HttpResponse run() { 
        try {  
         HttpUriRequest request = new HttpGet(url); 
         HttpClient spnegoHttpClient = buildSpengoHttpClient(); 
         httpResponse = spnegoHttpClient.execute(request); 
               return httpResponse; 
        } catch (IOException ioe) { 
         ioe.printStackTrace(); 
        } 
        return httpResponse; 
       } 
      }); 
     } catch (Exception le) { 
      le.printStackTrace();; 
     } 
     return null; 
    } 

    public static void main(String[] args) throws UnsupportedOperationException, IOException { 
     KerberosHttpClient restTest = new KerberosHttpClient("HTTP/[email protected]", 
       "file://C://Development//test.keytab", true); 
     HttpResponse response = restTest.callRestUrl("http://test.com/service/employees", 
       "HTTP/[email protected]"); 
     InputStream is = response.getEntity().getContent(); 
     System.out.println("Status code " + response.getStatusLine().getStatusCode()); 
     System.out.println(Arrays.deepToString(response.getAllHeaders())); 
     System.out.println(new String(IOUtils.toByteArray(is), "UTF-8")); 
    } 
}