001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 package org.apache.hadoop.fs.http.client; 019 020 021 import org.apache.hadoop.classification.InterfaceAudience; 022 import org.apache.hadoop.fs.Path; 023 import org.apache.hadoop.security.SecurityUtil; 024 import org.apache.hadoop.security.authentication.client.AuthenticatedURL; 025 import org.apache.hadoop.security.authentication.client.AuthenticationException; 026 import org.apache.hadoop.security.authentication.client.Authenticator; 027 import org.apache.hadoop.security.authentication.client.KerberosAuthenticator; 028 import org.apache.hadoop.security.token.Token; 029 import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenIdentifier; 030 import org.json.simple.JSONObject; 031 032 import java.io.IOException; 033 import java.net.HttpURLConnection; 034 import java.net.InetSocketAddress; 035 import java.net.URI; 036 import java.net.URL; 037 import java.util.HashMap; 038 import java.util.Map; 039 040 /** 041 * A <code>KerberosAuthenticator</code> subclass that fallback to 042 * {@link HttpFSPseudoAuthenticator}. 043 */ 044 @InterfaceAudience.Private 045 public class HttpFSKerberosAuthenticator extends KerberosAuthenticator { 046 047 /** 048 * Returns the fallback authenticator if the server does not use 049 * Kerberos SPNEGO HTTP authentication. 050 * 051 * @return a {@link HttpFSPseudoAuthenticator} instance. 052 */ 053 @Override 054 protected Authenticator getFallBackAuthenticator() { 055 return new HttpFSPseudoAuthenticator(); 056 } 057 058 private static final String HTTP_GET = "GET"; 059 private static final String HTTP_PUT = "PUT"; 060 061 public static final String DELEGATION_PARAM = "delegation"; 062 public static final String TOKEN_PARAM = "token"; 063 public static final String RENEWER_PARAM = "renewer"; 064 public static final String DELEGATION_TOKEN_JSON = "Token"; 065 public static final String DELEGATION_TOKEN_URL_STRING_JSON = "urlString"; 066 public static final String RENEW_DELEGATION_TOKEN_JSON = "long"; 067 068 /** 069 * DelegationToken operations. 070 */ 071 @InterfaceAudience.Private 072 public static enum DelegationTokenOperation { 073 GETDELEGATIONTOKEN(HTTP_GET, true), 074 RENEWDELEGATIONTOKEN(HTTP_PUT, true), 075 CANCELDELEGATIONTOKEN(HTTP_PUT, false); 076 077 private String httpMethod; 078 private boolean requiresKerberosCredentials; 079 080 private DelegationTokenOperation(String httpMethod, 081 boolean requiresKerberosCredentials) { 082 this.httpMethod = httpMethod; 083 this.requiresKerberosCredentials = requiresKerberosCredentials; 084 } 085 086 public String getHttpMethod() { 087 return httpMethod; 088 } 089 090 public boolean requiresKerberosCredentials() { 091 return requiresKerberosCredentials; 092 } 093 094 } 095 096 public static void injectDelegationToken(Map<String, String> params, 097 Token<?> dtToken) 098 throws IOException { 099 if (dtToken != null) { 100 params.put(DELEGATION_PARAM, dtToken.encodeToUrlString()); 101 } 102 } 103 104 private boolean hasDelegationToken(URL url) { 105 return url.getQuery().contains(DELEGATION_PARAM + "="); 106 } 107 108 @Override 109 public void authenticate(URL url, AuthenticatedURL.Token token) 110 throws IOException, AuthenticationException { 111 if (!hasDelegationToken(url)) { 112 super.authenticate(url, token); 113 } 114 } 115 116 public static final String OP_PARAM = "op"; 117 118 public static Token<?> getDelegationToken(URI fsURI, 119 InetSocketAddress httpFSAddr, AuthenticatedURL.Token token, 120 String renewer) throws IOException { 121 DelegationTokenOperation op = 122 DelegationTokenOperation.GETDELEGATIONTOKEN; 123 Map<String, String> params = new HashMap<String, String>(); 124 params.put(OP_PARAM, op.toString()); 125 params.put(RENEWER_PARAM,renewer); 126 URL url = HttpFSUtils.createURL(new Path(fsURI), params); 127 AuthenticatedURL aUrl = 128 new AuthenticatedURL(new HttpFSKerberosAuthenticator()); 129 try { 130 HttpURLConnection conn = aUrl.openConnection(url, token); 131 conn.setRequestMethod(op.getHttpMethod()); 132 HttpFSUtils.validateResponse(conn, HttpURLConnection.HTTP_OK); 133 JSONObject json = (JSONObject) ((JSONObject) 134 HttpFSUtils.jsonParse(conn)).get(DELEGATION_TOKEN_JSON); 135 String tokenStr = (String) 136 json.get(DELEGATION_TOKEN_URL_STRING_JSON); 137 Token<AbstractDelegationTokenIdentifier> dToken = 138 new Token<AbstractDelegationTokenIdentifier>(); 139 dToken.decodeFromUrlString(tokenStr); 140 SecurityUtil.setTokenService(dToken, httpFSAddr); 141 return dToken; 142 } catch (AuthenticationException ex) { 143 throw new IOException(ex.toString(), ex); 144 } 145 } 146 147 public static long renewDelegationToken(URI fsURI, 148 AuthenticatedURL.Token token, Token<?> dToken) throws IOException { 149 Map<String, String> params = new HashMap<String, String>(); 150 params.put(OP_PARAM, 151 DelegationTokenOperation.RENEWDELEGATIONTOKEN.toString()); 152 params.put(TOKEN_PARAM, dToken.encodeToUrlString()); 153 URL url = HttpFSUtils.createURL(new Path(fsURI), params); 154 AuthenticatedURL aUrl = 155 new AuthenticatedURL(new HttpFSKerberosAuthenticator()); 156 try { 157 HttpURLConnection conn = aUrl.openConnection(url, token); 158 conn.setRequestMethod( 159 DelegationTokenOperation.RENEWDELEGATIONTOKEN.getHttpMethod()); 160 HttpFSUtils.validateResponse(conn, HttpURLConnection.HTTP_OK); 161 JSONObject json = (JSONObject) ((JSONObject) 162 HttpFSUtils.jsonParse(conn)).get(DELEGATION_TOKEN_JSON); 163 return (Long)(json.get(RENEW_DELEGATION_TOKEN_JSON)); 164 } catch (AuthenticationException ex) { 165 throw new IOException(ex.toString(), ex); 166 } 167 } 168 169 public static void cancelDelegationToken(URI fsURI, 170 AuthenticatedURL.Token token, Token<?> dToken) throws IOException { 171 Map<String, String> params = new HashMap<String, String>(); 172 params.put(OP_PARAM, 173 DelegationTokenOperation.CANCELDELEGATIONTOKEN.toString()); 174 params.put(TOKEN_PARAM, dToken.encodeToUrlString()); 175 URL url = HttpFSUtils.createURL(new Path(fsURI), params); 176 AuthenticatedURL aUrl = 177 new AuthenticatedURL(new HttpFSKerberosAuthenticator()); 178 try { 179 HttpURLConnection conn = aUrl.openConnection(url, token); 180 conn.setRequestMethod( 181 DelegationTokenOperation.CANCELDELEGATIONTOKEN.getHttpMethod()); 182 HttpFSUtils.validateResponse(conn, HttpURLConnection.HTTP_OK); 183 } catch (AuthenticationException ex) { 184 throw new IOException(ex.toString(), ex); 185 } 186 } 187 188 }