Kerberos connection using HTTP Client

后端 未结 3 1845
猫巷女王i
猫巷女王i 2021-02-06 08:27

I\'m writing HTTP connection with Kerberos authentication. I have \"HTTP/1.1 401 Unauthorized\". Could you recommend me what I should check? I think there\'s somethink trick, bu

相关标签:
3条回答
  • 2021-02-06 08:39

    SPNEGO will not work because you use localhost as URL hostname.

    Your server is configured for a set of SPNs (or at least one) beginning with HTTP/ registered on the ActiveDirectory service account. You can query them from AD thanks to setspn -l yourServiceAccount.

    Your URL must use an effective server hostname known as SPN in ActiveDirectory so that Apache Http Client can negotiate a TGS for this service and send it to your server.

    0 讨论(0)
  • 2021-02-06 08:39

    Here is a test client I wrote in my project. This client relies on all encryption types to be enabled on JDK,

    If you see following in your logs and your keytab is encrypted at 256 bit default etypes for default_tkt_enctypes: 17 16 23 1 3.

    then following jar http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html needs to be downloaded and placed in JDK/jre/lib/security to enable AES256 bit encryption after that you should see following in logs default etypes for 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;
    

    Utility class

    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/test@test.com",
                    "file://C://Development//test.keytab", true);
            HttpResponse response = restTest.callRestUrl("http://test.com/service/employees",
                    "HTTP/test@test.com");
            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"));
        }
    }
    
    0 讨论(0)
  • 2021-02-06 08:53

    I had the same problem and just found your post. I bookmarked it so I can post an answer when I fixed it. I post a link to my question where someone answered it, so if someone finds this via Google they find the answer:

    HttpClient has problem creating the SPN for the AD when the URL has a port.

    See my question + answer here: HttpClient check Kerberos secured webpage. NTLM login didn't work

    0 讨论(0)
提交回复
热议问题