Hadoop 認證模塊詳解
客戶(hù)端認證
客戶(hù)端的入口函數為 KerberosAuthenticator.authenticate函數
連接HTTP服務(wù)端
HttpURLConnection conn = token.openConnection(url, connConfigurator);
conn.setRequestMethod(AUTH_HTTP_METHOD);
conn.connect();
SPNEGO認證
對于普通的HTTP的kerberos認證(SPNEGO),需要現在客戶(hù)端登錄KDC服務(wù)。核心代碼在函數doSpnegoSequence里面。
首先需要登錄KDC服務(wù)端:
subject = new Subject();
LoginContext login = new LoginContext("", subject,
null, new KerberosConfiguration());
// 登錄KDC服務(wù)
login.login();
下面主要是開(kāi)始認證的時(shí)候的邏輯。核心處理邏輯流程圖如下:
主要代碼邏輯如下。
GSSManager gssManager = GSSManager.getInstance();
// 設置服務(wù)端的域名,由于是HTTP協(xié)議,所以當前要求principal的格式為:HTTP/HOST_NAME的方式。
String servicePrincipal = KerberosUtil.getServicePrincipal("HTTP",
KerberosAuthenticator.this.url.getHost());
Oid oid = KerberosUtil.NT_GSS_KRB5_PRINCIPAL_OID;
GSSName serviceName = gssManager.createName(servicePrincipal,
oid);
oid = KerberosUtil.GSS_KRB5_MECH_OID;
// 創(chuàng )建獲取token的上下文信息。
gssContext = gssManager.createContext(serviceName, oid, null,
GSSContext.DEFAULT_LIFETIME);
gssContext.requestCredDeleg(true);
gssContext.requestMutualAuth(true);
byte[] inToken = new byte[0];
byte[] outToken;
boolean established = false;
// Loop while the context is still not established
while (!established) {
HttpURLConnection conn =
token.openConnection(url, connConfigurator);
// 獲取客戶(hù)端的token。對于第一次的場(chǎng)景,inToken為空。
// 對于中間過(guò)程,需要將服務(wù)端給的token傳進(jìn)去校驗。
outToken = gssContext.initSecContext(inToken, 0, inToken.length);
if (outToken != null) {
// 將token發(fā)送給服務(wù)端
sendToken(conn, outToken);
}
if (!gssContext.isEstablished()) {
// 讀取服務(wù)端發(fā)送的token。
inToken = readToken(conn);
} else {
// 認證完成,認證結束
established = true;
}
}
認證完成/無(wú)須認證
如果HTTP服務(wù)端返回的是HTTP_OK,則認為服務(wù)端是不需要認證的,或者是已經(jīng)認證完成了。在已經(jīng)完成認證的場(chǎng)景下,
需要解析Token。
AuthenticatedURL.extractToken(conn, token);
if (isTokenKerberos(token)) {
return;
}
needFallback = true;
其他自定義
其他自定義認證的場(chǎng)景,可以通過(guò)指定Authenticator的方式實(shí)現,具體實(shí)現可以自定義,主要保證服務(wù)端和客戶(hù)端一致即可。
// 當前主要適用于對認證方式需要擴展的場(chǎng)景。
Authenticator auth = getFallBackAuthenticator();
auth.setConnectionConfigurator(connConfigurator);
auth.authenticate(url, token);
服務(wù)端認證
初始化
服務(wù)端初始化的入口函數類(lèi)為AuthenticationFilter, 可以在web啟動(dòng)的時(shí)候將當前filter配置為AuthenticationFilter。用來(lái)實(shí)現服務(wù)端認證功能。
其中函數init為filter的初始化函數,主要作用是加載authHandler以及其他參數。在加載完authHandler之后會(huì )調用authHandler的init函數。
用來(lái)初始化authHandler。KerberosAuthenticationHandler就是一種authHandler。在初始化的時(shí)候會(huì )加載keytab和principal等信息。
并且初試化gssManager。
認證
認證的入口函數filter函數。對于大部分的authHandler,最終認證都是調用authHandler的authenticate函數。針對KerberosAuthenticationHandler來(lái)講。
在需要認證的時(shí)候返回401,如下代碼:
response.setHeader(WWW_AUTHENTICATE, KerberosAuthenticator.NEGOTIATE);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
通過(guò)下面代碼獲取客戶(hù)端Token??蛻?hù)端的Token對應的keytab必須包含HTTP/*
authorization = authorization.substring(KerberosAuthenticator.NEGOTIATE.length()).trim();
final Base64 base64 = new Base64(0);
final byte[] clientToken = base64.decode(authorization);
在與客戶(hù)端的認證的過(guò)程中,可能會(huì )需要多次交換token(參考客戶(hù)端流程),如果是在交互過(guò)程中,http請求的返回碼是401。如果認證成功,狀態(tài)碼則是200.
