You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@druid.apache.org by jo...@apache.org on 2019/05/23 20:15:54 UTC
[incubator-druid] branch master updated: Remove unnecessary
principal handling in KerberosAuthenticator (#7685)
This is an automated email from the ASF dual-hosted git repository.
jonwei pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-druid.git
The following commit(s) were added to refs/heads/master by this push:
new 54b3f36 Remove unnecessary principal handling in KerberosAuthenticator (#7685)
54b3f36 is described below
commit 54b3f363c4fc73fcc47b757bda8071a877b967f9
Author: Jonathan Wei <jo...@users.noreply.github.com>
AuthorDate: Thu May 23 13:15:44 2019 -0700
Remove unnecessary principal handling in KerberosAuthenticator (#7685)
---
.../security/kerberos/KerberosAuthenticator.java | 125 +++------------------
1 file changed, 13 insertions(+), 112 deletions(-)
diff --git a/extensions-core/druid-kerberos/src/main/java/org/apache/druid/security/kerberos/KerberosAuthenticator.java b/extensions-core/druid-kerberos/src/main/java/org/apache/druid/security/kerberos/KerberosAuthenticator.java
index d7edfaa..801d394 100644
--- a/extensions-core/druid-kerberos/src/main/java/org/apache/druid/security/kerberos/KerberosAuthenticator.java
+++ b/extensions-core/druid-kerberos/src/main/java/org/apache/druid/security/kerberos/KerberosAuthenticator.java
@@ -43,20 +43,9 @@ import org.apache.hadoop.security.authentication.util.SignerException;
import org.apache.hadoop.security.authentication.util.SignerSecretProvider;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.http.HttpHeader;
-import sun.security.krb5.EncryptedData;
-import sun.security.krb5.EncryptionKey;
-import sun.security.krb5.internal.APReq;
-import sun.security.krb5.internal.EncTicketPart;
-import sun.security.krb5.internal.Krb5;
-import sun.security.krb5.internal.Ticket;
-import sun.security.krb5.internal.crypto.KeyUsage;
-import sun.security.util.DerInputStream;
-import sun.security.util.DerValue;
import javax.security.auth.Subject;
-import javax.security.auth.kerberos.KerberosKey;
import javax.security.auth.kerberos.KerberosPrincipal;
-import javax.security.auth.kerberos.KeyTab;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
@@ -89,7 +78,6 @@ import java.util.Properties;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ThreadLocalRandom;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -230,56 +218,36 @@ public class KerberosAuthenticator implements Authenticator
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException
{
- HttpServletRequest httpReq = (HttpServletRequest) request;
-
// If there's already an auth result, then we have authenticated already, skip this.
if (request.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT) != null) {
filterChain.doFilter(request, response);
return;
}
+ // In the hadoop-auth 2.7.3 code that this was adapted from, the login would've occurred during init() of
+ // the AuthenticationFilter via `initializeAuthHandler(authHandlerClassName, filterConfig)`.
+ // Since we co-exist with other authentication schemes, don't login until we've checked that
+ // some other Authenticator didn't already validate this request.
if (loginContext == null) {
initializeKerberosLogin();
}
+ // Checking for excluded paths is Druid-specific, not from hadoop-auth
String path = ((HttpServletRequest) request).getRequestURI();
if (isExcluded(path)) {
filterChain.doFilter(request, response);
} else {
- String clientPrincipal;
- try {
- Cookie[] cookies = httpReq.getCookies();
- if (cookies == null) {
- clientPrincipal = getPrincipalFromRequestNew((HttpServletRequest) request);
- } else {
- clientPrincipal = null;
- for (Cookie cookie : cookies) {
- if ("hadoop.auth".equals(cookie.getName())) {
- Matcher matcher = HADOOP_AUTH_COOKIE_REGEX.matcher(cookie.getValue());
- if (matcher.matches()) {
- clientPrincipal = matcher.group(1);
- break;
- }
- }
- }
- }
- }
- catch (Exception ex) {
- clientPrincipal = null;
- }
-
- if (clientPrincipal != null) {
- request.setAttribute(
- AuthConfig.DRUID_AUTHENTICATION_RESULT,
- new AuthenticationResult(clientPrincipal, authorizerName, name, null)
- );
- }
+ // Run the original doFilter method, but with modifications to error handling
+ doFilterSuper(request, response, filterChain);
}
-
- doFilterSuper(request, response, filterChain);
}
- // Copied from hadoop-auth's AuthenticationFilter, to allow us to change error response handling
+
+ /**
+ * Copied from hadoop-auth 2.7.3 AuthenticationFilter, to allow us to change error response handling.
+ * Specifically, we want to defer the sending of 401 Unauthorized so that other Authenticators later in the chain
+ * can check the request.
+ */
private void doFilterSuper(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException
{
@@ -550,73 +518,6 @@ public class KerberosAuthenticator implements Authenticator
}
}
- private String getPrincipalFromRequestNew(HttpServletRequest req)
- {
- String authorization = req.getHeader(org.apache.hadoop.security.authentication.client.KerberosAuthenticator.AUTHORIZATION);
- if (authorization == null
- || !authorization.startsWith(org.apache.hadoop.security.authentication.client.KerberosAuthenticator.NEGOTIATE)) {
- return null;
- } else {
- authorization = authorization.substring(org.apache.hadoop.security.authentication.client.KerberosAuthenticator.NEGOTIATE
- .length()).trim();
- final byte[] clientToken = StringUtils.decodeBase64String(authorization);
- try {
- DerInputStream ticketStream = new DerInputStream(clientToken);
- DerValue[] values = ticketStream.getSet(clientToken.length, true);
-
- // see this link for AP-REQ format: https://tools.ietf.org/html/rfc1510#section-5.5.1
- for (DerValue value : values) {
- if (isValueAPReq(value)) {
- APReq apReq = new APReq(value);
- Ticket ticket = apReq.ticket;
- EncryptedData encData = ticket.encPart;
- int eType = encData.getEType();
-
- // find the server's key
- EncryptionKey finalKey = null;
- Subject serverSubj = loginContext.getSubject();
- Set<Object> serverCreds = serverSubj.getPrivateCredentials(Object.class);
- for (Object cred : serverCreds) {
- if (cred instanceof KeyTab) {
- KeyTab serverKeyTab = (KeyTab) cred;
- KerberosPrincipal kerberosPrincipal = new KerberosPrincipal(serverPrincipal);
- KerberosKey[] serverKeys = serverKeyTab.getKeys(kerberosPrincipal);
- for (KerberosKey key : serverKeys) {
- if (key.getKeyType() == eType) {
- finalKey = new EncryptionKey(key.getKeyType(), key.getEncoded());
- break;
- }
- }
- }
- }
-
- if (finalKey == null) {
- log.error("Could not find matching key from server creds.");
- return null;
- }
-
- // decrypt the ticket with the server's key
- byte[] decryptedBytes = encData.decrypt(finalKey, KeyUsage.KU_TICKET);
- decryptedBytes = encData.reset(decryptedBytes);
- EncTicketPart decrypted = new EncTicketPart(decryptedBytes);
- String clientPrincipal = decrypted.cname.toString();
- return clientPrincipal;
- }
- }
- }
- catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- }
-
- return null;
- }
-
- private boolean isValueAPReq(DerValue value)
- {
- return value.isConstructed((byte) Krb5.KRB_AP_REQ);
- }
-
private void initializeKerberosLogin() throws ServletException
{
String keytab;
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org