0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 package org.apache.hive.service.auth;
0020
0021 import java.security.AccessControlContext;
0022 import java.security.AccessController;
0023 import java.security.PrivilegedExceptionAction;
0024 import java.util.Arrays;
0025 import java.util.HashMap;
0026 import java.util.HashSet;
0027 import java.util.Map;
0028 import java.util.Random;
0029 import java.util.Set;
0030 import java.util.StringTokenizer;
0031
0032 import javax.security.auth.Subject;
0033
0034 import org.apache.commons.codec.binary.Base64;
0035 import org.apache.commons.logging.Log;
0036 import org.apache.commons.logging.LogFactory;
0037 import org.apache.hadoop.hive.shims.ShimLoader;
0038 import org.apache.hadoop.security.UserGroupInformation;
0039 import org.apache.http.protocol.BasicHttpContext;
0040 import org.apache.http.protocol.HttpContext;
0041 import org.ietf.jgss.GSSContext;
0042 import org.ietf.jgss.GSSManager;
0043 import org.ietf.jgss.GSSName;
0044 import org.ietf.jgss.Oid;
0045
0046
0047
0048
0049 public final class HttpAuthUtils {
0050 public static final String WWW_AUTHENTICATE = "WWW-Authenticate";
0051 public static final String AUTHORIZATION = "Authorization";
0052 public static final String BASIC = "Basic";
0053 public static final String NEGOTIATE = "Negotiate";
0054 private static final Log LOG = LogFactory.getLog(HttpAuthUtils.class);
0055 private static final String COOKIE_ATTR_SEPARATOR = "&";
0056 private static final String COOKIE_CLIENT_USER_NAME = "cu";
0057 private static final String COOKIE_CLIENT_RAND_NUMBER = "rn";
0058 private static final String COOKIE_KEY_VALUE_SEPARATOR = "=";
0059 private static final Set<String> COOKIE_ATTRIBUTES =
0060 new HashSet<String>(Arrays.asList(COOKIE_CLIENT_USER_NAME, COOKIE_CLIENT_RAND_NUMBER));
0061
0062
0063
0064
0065
0066 public static String getKerberosServiceTicket(String principal, String host,
0067 String serverHttpUrl, boolean assumeSubject) throws Exception {
0068 String serverPrincipal =
0069 ShimLoader.getHadoopThriftAuthBridge().getServerPrincipal(principal, host);
0070 if (assumeSubject) {
0071
0072
0073 AccessControlContext context = AccessController.getContext();
0074 Subject subject = Subject.getSubject(context);
0075 if (subject == null) {
0076 throw new Exception("The Subject is not set");
0077 }
0078 return Subject.doAs(subject, new HttpKerberosClientAction(serverPrincipal, serverHttpUrl));
0079 } else {
0080
0081 UserGroupInformation clientUGI =
0082 ShimLoader.getHadoopThriftAuthBridge().getCurrentUGIWithConf("kerberos");
0083 return clientUGI.doAs(new HttpKerberosClientAction(serverPrincipal, serverHttpUrl));
0084 }
0085 }
0086
0087
0088
0089
0090
0091
0092
0093
0094 public static String createCookieToken(String clientUserName) {
0095 StringBuffer sb = new StringBuffer();
0096 sb.append(COOKIE_CLIENT_USER_NAME).append(COOKIE_KEY_VALUE_SEPARATOR).append(clientUserName)
0097 .append(COOKIE_ATTR_SEPARATOR);
0098 sb.append(COOKIE_CLIENT_RAND_NUMBER).append(COOKIE_KEY_VALUE_SEPARATOR)
0099 .append((new Random(System.currentTimeMillis())).nextLong());
0100 return sb.toString();
0101 }
0102
0103
0104
0105
0106
0107
0108 public static String getUserNameFromCookieToken(String tokenStr) {
0109 Map<String, String> map = splitCookieToken(tokenStr);
0110
0111 if (!map.keySet().equals(COOKIE_ATTRIBUTES)) {
0112 LOG.error("Invalid token with missing attributes " + tokenStr);
0113 return null;
0114 }
0115 return map.get(COOKIE_CLIENT_USER_NAME);
0116 }
0117
0118
0119
0120
0121
0122
0123
0124 private static Map<String, String> splitCookieToken(String tokenStr) {
0125 Map<String, String> map = new HashMap<String, String>();
0126 StringTokenizer st = new StringTokenizer(tokenStr, COOKIE_ATTR_SEPARATOR);
0127
0128 while (st.hasMoreTokens()) {
0129 String part = st.nextToken();
0130 int separator = part.indexOf(COOKIE_KEY_VALUE_SEPARATOR);
0131 if (separator == -1) {
0132 LOG.error("Invalid token string " + tokenStr);
0133 return null;
0134 }
0135 String key = part.substring(0, separator);
0136 String value = part.substring(separator + 1);
0137 map.put(key, value);
0138 }
0139 return map;
0140 }
0141
0142
0143 private HttpAuthUtils() {
0144 throw new UnsupportedOperationException("Can't initialize class");
0145 }
0146
0147
0148
0149
0150
0151 public static class HttpKerberosClientAction implements PrivilegedExceptionAction<String> {
0152 public static final String HTTP_RESPONSE = "HTTP_RESPONSE";
0153 public static final String SERVER_HTTP_URL = "SERVER_HTTP_URL";
0154 private final String serverPrincipal;
0155 private final String serverHttpUrl;
0156 private final Base64 base64codec;
0157 private final HttpContext httpContext;
0158
0159 public HttpKerberosClientAction(String serverPrincipal, String serverHttpUrl) {
0160 this.serverPrincipal = serverPrincipal;
0161 this.serverHttpUrl = serverHttpUrl;
0162 base64codec = new Base64(0);
0163 httpContext = new BasicHttpContext();
0164 httpContext.setAttribute(SERVER_HTTP_URL, serverHttpUrl);
0165 }
0166
0167 @Override
0168 public String run() throws Exception {
0169
0170 Oid mechOid = new Oid("1.2.840.113554.1.2.2");
0171
0172 Oid krb5PrincipalOid = new Oid("1.2.840.113554.1.2.2.1");
0173 GSSManager manager = GSSManager.getInstance();
0174
0175 GSSName serverName = manager.createName(serverPrincipal, krb5PrincipalOid);
0176
0177
0178 GSSContext gssContext =
0179 manager.createContext(serverName, mechOid, null, GSSContext.DEFAULT_LIFETIME);
0180 gssContext.requestMutualAuth(false);
0181
0182 byte[] inToken = new byte[0];
0183 byte[] outToken = gssContext.initSecContext(inToken, 0, inToken.length);
0184 gssContext.dispose();
0185
0186 return new String(base64codec.encode(outToken));
0187 }
0188 }
0189 }