場景:cdh叢集已經添加kerberos認證,但是需要通路httpfs服務,怎麼辦?
如下實作:
1、引入maven
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yjf</groupId>
<artifactId>test-java</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!--Add maven release-->
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<encoding>UTF-8</encoding>
<!--Junit -->
<junit.version>4.12</junit.version>
<!--Slf4j-->
<slf4j-version>1.7.20</slf4j-version>
<!--mysql-->
<mysql.driver.version>5.1.38</mysql.driver.version>
<!--httpclient-->
<httpclient.version>4.3.3</httpclient.version>
<!--coomon-io -->
<common.verion>2.5</common.verion>
</properties>
<repositories>
<repository>
<id>cloudera</id>
<url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
</repository>
<repository>
<id>mvnrepository</id>
<url>https://mvnrepository.com/artifact/</url>
</repository>
</repositories>
<dependencies>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${common.verion}</version>
</dependency>
<!--Httpclient-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>${httpclient.version}</version>
</dependency>
<!--Junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!--slf4j-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j-version}</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.driver.version}</version>
</dependency>
</dependencies>
<!--maven打包-->
<build>
<finalName>test-java</finalName>
<sourceDirectory>src/main/java</sourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
</build>
</project>
2、實作的代碼:
package com.yjf.java.utils;
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.HttpClient;
import org.apache.http.client.config.AuthSchemes;
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.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by root on 20180118.
* Update date:
* <p>
* Time: 11:21 AM
* Project: test-java
* Package: com.yjf.java.utils
* Describe :
* <p>
* Result of Test: test ok
* Command:
* <p>
* <p>
*
* Status:Using online
* Attention:
*/
public class RequestKerberosUrlUtils {
public static Logger logger = LoggerFactory.getLogger(RequestKerberosUrlUtils.class);
private String principal;
private String keyTabLocation;
public RequestKerberosUrlUtils() {
}
public RequestKerberosUrlUtils(String principal, String keyTabLocation) {
super();
this.principal = principal;
this.keyTabLocation = keyTabLocation;
}
public RequestKerberosUrlUtils(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 RequestKerberosUrlUtils(String principal, String keyTabLocation, String krb5Location, boolean isDebug) {
this(principal, keyTabLocation, isDebug);
System.setProperty("java.security.krb5.conf", krb5Location);
}
//模拟curl使用kerberos認證
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) {
logger.warn(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 {
//認證子產品:Krb5Login
LoginContext lc = new LoginContext("Krb5Login", 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;
}
}
測試類
package com.test.java.Thread;
import com.yjf.java.utils.RequestKerberosUrlUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.util.Arrays;
/**
* Created by root on 20180118.
* Update date:
* <p>
* Time: 11:34 AM
* Project: test-java
* Package: com.test.java.Thread
* Describe :
* <p>
* Result of Test: test ok,test error
* Command:
* <p>
* <p>
*
* Status:Using online
* Attention:
*/
public class TestSendHttpRequestToUrl {
private static Logger logger= LoggerFactory.getLogger(TestSendHttpRequestToUrl.class);
public static void main(String[] args) {
String user ="[email protected]";
String keytab="/home/spark/conf/yourUser.keytab";
String krb5Location="/etc/krb5.conf";
try{
RequestKerberosUrlUtils restTest = new RequestKerberosUrlUtils(user,keytab,krb5Location, false);
// refer to https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/WebHDFS.html#Open_and_Read_a_File
// list dir
String url_liststatus="http://activeNamenodeHost:50070/webhdfs/v1/user/cdnportal/data/release?op=liststatus";
// location
String url_get_block_locations="http://activeNamenodeHost:50070/webhdfs/v1/user/cdnportal/data/release/world.txt?op=get_block_locations";
HttpResponse response = restTest.callRestUrl(url_liststatus,user);
// HttpResponse response = restTest.callRestUrl(url_get_block_locations,user);
InputStream is = response.getEntity().getContent();
System.out.println("Status code " + response.getStatusLine().getStatusCode());
System.out.println("message is :"+ Arrays.deepToString(response.getAllHeaders()));
System.out.println("string:\n"+new String(IOUtils.toByteArray(is), "UTF-8"));
}catch (Exception exp){
exp.printStackTrace();
}
}
}