場景:開發中突然遇到了cannot get Kerberos realm的認證問題,但是Kerberos認證是必須的,又不能更改伺服器配置,業務代碼中該如何實作呢?
這是Kerberos認證問題,廢話不多說了,直接上代碼:
@Slf4j
public class KerberosUtils {
public static final KerberosUtils singleton = new KerberosUtils();
public static final String KRB5_CONF_KEY = "java.security.krb5.conf";
public static final String HADOOP_AUTH_KEY = "hadoop.security.authentication";
public static final String KRB_STR = "Kerberos";
public static final String FALSE_STR = "false";
public static final String KRB5_DEBUG = "sun.security.krb5.debug";
public static final String SUBJECT_ONLY_KEY = "javax.security.auth.useSubjectCredsOnly";
public void loginFromKeytab(String kerberosUserName,
String keytabFile,
String kerberosPrincipal){
//事先kinit -kt 認證
execLocalCommands(buildKinit(keytabFile,kerberosPrincipal));
System.setProperty(KRB5_CONF_KEY,"/etc/krb5.conf");
String var1 = System.getProperty(KRB5_CONF_KEY);
System.out.println("conf::"+var1);
Configuration conf = new Configuration();
conf.set(HADOOP_AUTH_KEY, "Kerberos");
conf.setBoolean("hadoop.security.authorization", true);
UserGroupInformation.setConfiguration(conf);
try {
log.info("kerberos - userName:{},isLoginKeytabBased:{}", UserGroupInformation.getLoginUser().getUserName(), UserGroupInformation.isLoginKeytabBased());
UserGroupInformation.loginUserFromKeytab( kerberosUserName, keytabFile);
System.out.println("!(UserGroupInformation.getLoginUser().getUserName().equals(kerberosUserName):"+UserGroupInformation.getLoginUser().getUserName().equals(kerberosUserName));
} catch (IOException e) {
e.printStackTrace();
}
}
public String buildKinit(String keytabFile ,String kerberosPrincipal) {
String url = String.format("kinit -kt %s %s", keytabFile, kerberosPrincipal);
log.info("kerbers init : {}", url);
return url;
}
public UserGroupInformation loginAndReturnUgi(String principal, String keytabPath, String krb5confPath) throws IOException {
log.info("Kerberos login with principal: {} and keytab: {}", principal, keytabPath);
reloadKrb5conf(krb5confPath);
Configuration configuration = new Configuration();
configuration.set(HADOOP_AUTH_KEY, KRB_STR);
UserGroupInformation.setConfiguration(configuration);
return UserGroupInformation.loginUserFromKeytabAndReturnUGI(principal, keytabPath);
}
//在jaas.conf中為KRB5LoginModule設定refreshKrb5Config = true
public synchronized void reloadKrb5conf(String krb5confPath) {
System.setProperty(KRB5_CONF_KEY, krb5confPath);
// 不重新整理會讀/etc/krb5.conf
try {
Config.refresh();
String defaultRealm = KerberosUtil.getDefaultRealm();
} catch (KrbException e) {
log.warn( "resetting default realm failed, current default realm will still be used.", e);
}
}
private void execLocalCommands(String kinit){
try{
log.info("Now executed linux command is :{} ", kinit);//輸出下指令
final Process process = Runtime.getRuntime().exec(kinit);
new Thread(){
@Override
public void run(){
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
try{
while((line = in.readLine()) != null){
log.info("kinit input: " + line);
}
} catch (IOException e){
log.error(e.getMessage());
} finally {
in.close();
}
}.start();
new Thread(){
@Override
public void run(){
BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line = null;
try{
while((line = err.readLine()) != null){
log.info("kinit err: " + line);
}
} catch (IOException e){
log.error(e.getMessage());
}finally{
err.close();
}
}.start();
process.waitFor();
}catch (InterruptedException e) {
log.error(e.getMessage());
} catch (IOException e) {
log.error(e.getMessage());
}
}
}
調用該工具類
KerberosUtils.singleton.loginFromKeytab(db.getUserName(), db.getKerberosFile(), db.getKerberosPrincipal());
就OK了!
編輯